diff --git a/BUILD.gn b/BUILD.gn index 5d98ae835c28e592179515d4b092a9292dcd2aa9..6dce3edb72ace93760105185ce83a1b8fd8b8de6 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -215,6 +215,7 @@ config("ark_toolchain_public_config") { # ecmascript unit testcase config config("toolchain_test_config") { visibility = [ + "./inspector/test/*", "./test/fuzztest/*", "./tooling/test/*", "./websocket/test/*", @@ -243,6 +244,7 @@ group("ark_toolchain_unittest") { testonly = true deps = [] deps += [ + "./inspector/test:unittest", "./tooling/test:unittest", "./websocket/test:unittest", ] @@ -257,6 +259,7 @@ group("ark_toolchain_host_unittest") { # js unittest deps += [ + "./inspector/test:host_unittest", "./tooling/test:host_unittest", "./websocket/test:host_unittest", ] diff --git a/CODEOWNERS b/CODEOWNERS index a2ad37405ddc9bc4a4ccb9f7636c204c2518ac75..ece0249656096eadbe5d5522d9c01802a4429402 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -12,4 +12,5 @@ # limitations under the License. * @klooer +.* @klooer diff --git a/build/ark_var.gni b/build/ark_var.gni index 4739e0653338a1dd58cbadfa5136de0587772e88..001e4dc587af8619ea1568d54045b2013a1f0afe 100644 --- a/build/ark_var.gni +++ b/build/ark_var.gni @@ -17,4 +17,6 @@ declare_args() { # system package dir system_base_dir = "system" + + device_name = "" } diff --git a/build/compile_script/ark.py b/build/compile_script/ark.py index 53faada5da0d68c7e7e32805baa6ec6329143c2e..1f9fff0995936dce80d5ca9ffbf15cc4ebb1b10a 100755 --- a/build/compile_script/ark.py +++ b/build/compile_script/ark.py @@ -24,7 +24,7 @@ import os import platform import subprocess import sys -from typing import List, Tuple, Union, Optional +from typing import List, Any, Tuple, Union, Optional CURRENT_FILENAME = os.path.basename(__file__) @@ -96,7 +96,7 @@ class ArkPy: REGRESS_TEST_LOG_FILE_NAME = "regresstest.log" PREBUILTS_DOWNLOAD_CONFIG_FILE_PATH = \ "./arkcompiler/toolchain/build/prebuilts_download/prebuilts_download_config.json" - INDENTATION_STRING_PER_LEVEL = " " # for help message + INDENTATION_STRING_PER_LEVEL = " " # for help message # In ARG_DICT, "flags" and "description" are must-keys for the leaf-dicts in it. # (Future designer need know.) ARG_DICT = { @@ -221,14 +221,14 @@ class ArkPy: "gn_targets_depend_on": ["default"], }, "gn_target": { - "flags": [""], # any other flags + "flags": [""], # any other flags "description": "Build for arkcompiler target assigned by user. Targets include group(ets_runtime), " "ohos_executable(ark_js_vm), ohos_shared_library(libark_jsruntime), " "ohos_static_library(static_icuuc), ohos_source_set(libark_jsruntime_set), " "ohos_unittest(EcmaVm_001_Test), action(EcmaVm_001_TestAction) and other target of user-defined " "template type in \"*.gn*\" file.", - "gn_targets_depend_on": [], # not need, depend on deps of itself in "*.gn*" file + "gn_targets_depend_on": [], # not need, depend on deps of itself in "*.gn*" file }, }, "option": { @@ -264,7 +264,7 @@ class ArkPy: "keep-going": { "flags": ["--keep-going=*", "-keep-going=*"], "description": "Keep running unittest etc. until errors occured less than N times" - " (use 0 to ignore all errors).", + " (use 0 to ignore all errors).", }, }, "help": { @@ -289,7 +289,7 @@ class ArkPy: arg_list = list(dict.fromkeys(arg_list)) # match [help] flag if len(arg_list) == 0 or ( - True in [self.is_dict_flags_match_arg(self.ARG_DICT["help"], arg) for arg in arg_list]): + True in [self.is_dict_flags_match_arg(self.ARG_DICT.get("help"), arg) for arg in arg_list]): print(self.get_help_msg_of_all()) return # match [[os_cpu].[mode]] flag @@ -307,155 +307,229 @@ class ArkPy: if fnmatch(arg_to_match, flag): return True return False - + @staticmethod - def get_test262_cmd(gn_args, out_path, x64_out_path, run_pgo, enable_litecg, args_to_test262_cmd, - timeout): - - print("running test262 in AsmMode\n") - if any('target_cpu="arm64"' in arg for arg in gn_args): - test262_cmd = "cd arkcompiler/ets_frontend && python3 test262/run_test262.py {0} --timeout {3}" \ - " --libs-dir ../../{1}/arkcompiler/ets_runtime:../../{1}/thirdparty/icu:" \ - "../../{1}/thirdparty/zlib:../../prebuilts/clang/ohos/linux-x86_64/llvm/lib" \ - " --ark-arch aarch64" \ - " --ark-arch-root=../../{1}/common/common/libc/" \ - " --ark-tool=../../{1}/arkcompiler/ets_runtime/ark_js_vm" \ - " --ark-frontend-binary=../../{2}/arkcompiler/ets_frontend/es2abc" \ - " --merge-abc-binary=../../{2}/arkcompiler/ets_frontend/merge_abc" \ - " --ark-frontend=es2panda".format(args_to_test262_cmd, out_path, x64_out_path) + def libs_dir(is_arm, is_aot, is_pgo, out_dir, x64_out_dir) -> str: + if is_arm and is_aot and is_pgo: + return (f"--libs-dir ../../{out_dir}/arkcompiler/ets_runtime:" + f"../../{out_dir}/thirdparty/icu:" + f"../../{out_dir}/third_party/icu:" + f"../../thirdparty/zlib:" + f"../../prebuilts/clang/ohos/linux-x86_64/llvm/lib") + if is_arm and is_aot and not is_pgo: + return ("--libs-dir ../../prebuilts/clang/ohos/linux-x86_64/llvm/lib" + f":../../{x64_out_dir}/thirdparty/icu/") + if not is_arm and is_aot: + return (f"--libs-dir ../../{out_dir}/arkcompiler/ets_runtime" + f":../../{out_dir}/thirdparty/icu:" + f"../../{out_dir}/third_party/icu:" + f"../../thirdparty/zlib:" + f"../../prebuilts/clang/ohos/linux-x86_64/llvm/lib") + # not is_arm and not is_aot + return " --libs-dir ../../prebuilts/clang/ohos/linux-x86_64/llvm/lib" + + @staticmethod + def get_cmd(test_suite, test_script_name, test_script_path, gn_args, out_path, x64_out_path, aot_mode, run_pgo, + enable_litecg, args_to_cmd, timeout, ignore_list: Optional[str] = None): + cmd = [ + f"cd {test_script_path}", + f"&& python3 {test_script_name} {args_to_cmd}", + f"--timeout {timeout}", + f"--ark-tool=../../{out_path}/arkcompiler/ets_runtime/ark_js_vm", + "--ark-frontend=es2panda" + ] + is_arm = any('target_cpu="arm64"' in arg for arg in gn_args) + if is_arm: + cmd.append("--ark-arch aarch64") + cmd.append(f"--ark-arch-root=../../{out_path}/common/common/libc/") + cmd.append(f"--ark-frontend-binary=../../{x64_out_path}/arkcompiler/ets_frontend/es2abc") + cmd.append(f"--merge-abc-binary=../../{x64_out_path}/arkcompiler/ets_frontend/merge_abc") + if aot_mode: + cmd.append(f"--ark-aot-tool=../../{out_path}/arkcompiler/ets_runtime/ark_aot_compiler") + if test_suite == "regresstest": + cmd.append(f"--stub-path=../../{out_path}/gen/arkcompiler/ets_runtime/stub.an") else: - test262_cmd = "cd arkcompiler/ets_frontend && python3 test262/run_test262.py {0} --timeout {2}" \ - " --libs-dir ../../prebuilts/clang/ohos/linux-x86_64/llvm/lib" \ - " --ark-tool=../../{1}/arkcompiler/ets_runtime/ark_js_vm" \ - " --ark-frontend-binary=../../{1}/arkcompiler/ets_frontend/es2abc" \ - " --merge-abc-binary=../../{1}/arkcompiler/ets_frontend/merge_abc" \ - " --ark-frontend=es2panda".format(args_to_test262_cmd, out_path, timeout) - return test262_cmd + cmd.append(f"--ark-frontend-binary=../../{out_path}/arkcompiler/ets_frontend/es2abc") + cmd.append(f"--merge-abc-binary=../../{out_path}/arkcompiler/ets_frontend/merge_abc") + if aot_mode: + cmd.append(f"--ark-aot-tool=../../{out_path}/arkcompiler/ets_runtime/ark_aot_compiler") + if test_suite == "regresstest": + cmd.append(f"--stub-path=../../{out_path}/gen/arkcompiler/ets_runtime/stub.an") + + cmd.append(ArkPy.libs_dir( + is_arm=is_arm, + is_aot=aot_mode, + is_pgo=run_pgo, + out_dir=out_path, + x64_out_dir=x64_out_path + )) + + if aot_mode: + cmd.append("--ark-aot") + mode = ["AOT"] + if run_pgo: + cmd.append("--run-pgo") + mode.append("PGO") + if enable_litecg: + cmd.append("--enable-litecg") + mode.append("LiteCG") + mode_str = " ".join(mode) + print(f"Running {test_suite} in {mode_str} Mode\n") + + if test_suite == "regresstest" and ignore_list: + cmd.append(f"--ignore-list {ignore_list}") + + if test_suite == "regresstest": + cmd.append(f"--out-dir ../../{out_path}") + + return " ".join(cmd) @staticmethod def get_test262_aot_cmd(gn_args, out_path, x64_out_path, run_pgo, enable_litecg, args_to_test262_cmd, - timeout): + timeout): print("running test262 in AotMode\n") if any('target_cpu="arm64"' in arg for arg in gn_args): if run_pgo: - test262_cmd = "cd arkcompiler/ets_frontend && python3 test262/run_test262.py {0} --timeout {4}" \ - " --libs-dir ../../{1}/arkcompiler/ets_runtime:../../{1}/thirdparty/icu:" \ - "../../{1}/thirdparty/zlib:../../prebuilts/clang/ohos/linux-x86_64/llvm/lib" \ - " --ark-arch aarch64" \ - " --ark-arch-root=../../{1}/common/common/libc/" \ - " --ark-tool=../../{1}/arkcompiler/ets_runtime/ark_js_vm" \ - " --ark-aot-tool=../../{1}/arkcompiler/ets_runtime/ark_aot_compiler" \ - " --ark-frontend-binary=../../{2}/arkcompiler/ets_frontend/es2abc" \ - " --merge-abc-binary=../../{2}/arkcompiler/ets_frontend/merge_abc" \ - " --ark-aot" \ - " --ark-frontend=es2panda"\ - "{3}".format(args_to_test262_cmd, out_path, x64_out_path, " --run-pgo", timeout) + test262_cmd = f"cd arkcompiler/ets_frontend && python3 test262/run_test262.py {args_to_test262_cmd}" \ + f" --timeout {timeout}" \ + f" --libs-dir ../../{out_path}/arkcompiler/ets_runtime:../../{out_path}/thirdparty/icu:" \ + f"../../{out_path}/thirdparty/zlib:../../prebuilts/clang/ohos/linux-x86_64/llvm/lib" \ + " --ark-arch aarch64" \ + f" --ark-arch-root=../../{out_path}/common/common/libc/" \ + f" --ark-tool=../../{out_path}/arkcompiler/ets_runtime/ark_js_vm" \ + f" --ark-aot-tool=../../{out_path}/arkcompiler/ets_runtime/ark_aot_compiler" \ + f" --ark-frontend-binary=../../{x64_out_path}/arkcompiler/ets_frontend/es2abc" \ + f" --merge-abc-binary=../../{x64_out_path}/arkcompiler/ets_frontend/merge_abc" \ + " --ark-aot" \ + " --ark-frontend=es2panda" \ + " --run-pgo" else: test262_cmd = "cd arkcompiler/ets_frontend && python3 test262/run_test262.py {0} --timeout {3}" \ - " --libs-dir ../../prebuilts/clang/ohos/linux-x86_64/llvm/lib:../../{2}/thirdparty/icu/" \ - " --ark-arch aarch64" \ - " --ark-arch-root=../../{1}/common/common/libc/" \ - " --ark-aot" \ - " --ark-aot-tool=../../{2}/arkcompiler/ets_runtime/ark_aot_compiler" \ - " --ark-tool=../../{1}/arkcompiler/ets_runtime/ark_js_vm" \ - " --ark-frontend-binary=../../{2}/arkcompiler/ets_frontend/es2abc" \ - " --merge-abc-binary=../../{2}/arkcompiler/ets_frontend/merge_abc" \ - " --ark-frontend=es2panda".format(args_to_test262_cmd, out_path, x64_out_path, timeout) + " --libs-dir ../../prebuilts/clang/ohos/linux-x86_64/llvm/lib:../../{2}/thirdparty/icu/" \ + " --ark-arch aarch64" \ + " --ark-arch-root=../../{1}/common/common/libc/" \ + " --ark-aot" \ + " --ark-aot-tool=../../{2}/arkcompiler/ets_runtime/ark_aot_compiler" \ + " --ark-tool=../../{1}/arkcompiler/ets_runtime/ark_js_vm" \ + " --ark-frontend-binary=../../{2}/arkcompiler/ets_frontend/es2abc" \ + " --merge-abc-binary=../../{2}/arkcompiler/ets_frontend/merge_abc" \ + " --ark-frontend=es2panda".format(args_to_test262_cmd, out_path, x64_out_path, timeout) else: - test262_cmd = "cd arkcompiler/ets_frontend && python3 test262/run_test262.py {0} --timeout {3}" \ - " --libs-dir ../../{1}/arkcompiler/ets_runtime:../../{1}/thirdparty/icu" \ - ":../../{1}/thirdparty/zlib:../../prebuilts/clang/ohos/linux-x86_64/llvm/lib" \ - " --ark-tool=../../{1}/arkcompiler/ets_runtime/ark_js_vm" \ - " --ark-aot-tool=../../{1}/arkcompiler/ets_runtime/ark_aot_compiler" \ - " --ark-frontend-binary=../../{1}/arkcompiler/ets_frontend/es2abc" \ - " --merge-abc-binary=../../{1}/arkcompiler/ets_frontend/merge_abc" \ - " --ark-aot" \ - " --ark-frontend=es2panda"\ - "{2}".format(args_to_test262_cmd, out_path, " --run-pgo" if run_pgo else "", timeout) + run_pgo_arg = " --run-pgo" if run_pgo else "" + test262_cmd = f"cd arkcompiler/ets_frontend && python3 test262/run_test262.py {args_to_test262_cmd}" \ + f" --timeout {timeout}" \ + f" --libs-dir ../../{out_path}/arkcompiler/ets_runtime:../../{out_path}/thirdparty/icu" \ + f":../../{out_path}/thirdparty/zlib:../../prebuilts/clang/ohos/linux-x86_64/llvm/lib" \ + f" --ark-tool=../../{out_path}/arkcompiler/ets_runtime/ark_js_vm" \ + f" --ark-aot-tool=../../{out_path}/arkcompiler/ets_runtime/ark_aot_compiler" \ + f" --ark-frontend-binary=../../{out_path}/arkcompiler/ets_frontend/es2abc" \ + f" --merge-abc-binary=../../{out_path}/arkcompiler/ets_frontend/merge_abc" \ + " --ark-aot" \ + " --ark-frontend=es2panda" \ + f" {run_pgo_arg}" if enable_litecg: test262_cmd = test262_cmd + " --enable-litecg" return test262_cmd @staticmethod - def get_test262_jit_cmd(gn_args, out_path, x64_out_path, args_to_test262_cmd, timeout): - print("running test262 in JIT mode\n") + def get_jit_cmd(test_suite, test_script_name, test_script_path, gn_args, out_path, x64_out_path, args_to_cmd, + timeout): + print(f"running {test_suite} in JIT mode\n") if any('target_cpu="arm64"' in arg for arg in gn_args): - test262_cmd = "cd arkcompiler/ets_frontend && python3 test262/run_test262.py {0} --timeout {3}" \ - " --libs-dir ../../prebuilts/clang/ohos/linux-x86_64/llvm/lib:../../{1}/thirdparty/icu/" \ - ":../../{1}/thirdparty/bounds_checking_function" \ - ":../../{1}/arkcompiler/ets_runtime:" \ - " --ark-arch aarch64" \ - " --run-jit" \ - " --ark-arch-root=../../{1}/common/common/libc/" \ - " --ark-aot-tool=../../{2}/arkcompiler/ets_runtime/ark_aot_compiler" \ - " --ark-tool=../../{1}/arkcompiler/ets_runtime/ark_js_vm" \ - " --ark-frontend-binary=../../{2}/arkcompiler/ets_frontend/es2abc" \ - " --merge-abc-binary=../../{2}/arkcompiler/ets_frontend/merge_abc" \ - " --ark-frontend=es2panda".format(args_to_test262_cmd, out_path, x64_out_path, timeout) + cmd = f"cd {test_script_path} && python3 {test_script_name} {args_to_cmd} --timeout {timeout}" \ + f" --libs-dir ../../prebuilts/clang/ohos/linux-x86_64/llvm/lib:../../{out_path}/thirdparty/icu/" \ + f":../../{out_path}/thirdparty/bounds_checking_function" \ + f":../../{out_path}/arkcompiler/ets_runtime:" \ + " --ark-arch aarch64" \ + " --run-jit" \ + f" --ark-arch-root=../../{out_path}/common/common/libc/" \ + f" --ark-aot-tool=../../{x64_out_path}/arkcompiler/ets_runtime/ark_aot_compiler" \ + f" --ark-tool=../../{out_path}/arkcompiler/ets_runtime/ark_js_vm" \ + f" --ark-frontend-binary=../../{x64_out_path}/arkcompiler/ets_frontend/es2abc" \ + f" --merge-abc-binary=../../{x64_out_path}/arkcompiler/ets_frontend/merge_abc" \ + " --ark-frontend=es2panda" else: - test262_cmd = "cd arkcompiler/ets_frontend && python3 test262/run_test262.py {0} --timeout {3}" \ - " --libs-dir ../../{1}/arkcompiler/ets_runtime:../../{1}/thirdparty/icu" \ - ":../../{1}/thirdparty/zlib:../../prebuilts/clang/ohos/linux-x86_64/llvm/lib" \ - " --run-jit" \ - " --ark-tool=../../{1}/arkcompiler/ets_runtime/ark_js_vm" \ - " --ark-frontend-binary=../../{1}/arkcompiler/ets_frontend/es2abc" \ - " --merge-abc-binary=../../{1}/arkcompiler/ets_frontend/merge_abc" \ - " --ark-frontend=es2panda"\ - "{2}".format(args_to_test262_cmd, out_path, x64_out_path, timeout) - return test262_cmd - + cmd = f"cd arkcompiler/ets_frontend && python3 {test_script_name} {args_to_cmd} --timeout {timeout}" \ + f" --libs-dir ../../{out_path}/arkcompiler/ets_runtime:../../{out_path}/thirdparty/icu" \ + f":../../{out_path}/thirdparty/zlib:../../prebuilts/clang/ohos/linux-x86_64/llvm/lib" \ + " --run-jit" \ + f" --ark-tool=../../{out_path}/arkcompiler/ets_runtime/ark_js_vm" \ + f" --ark-frontend-binary=../../{out_path}/arkcompiler/ets_frontend/es2abc" \ + f" --merge-abc-binary=../../{out_path}/arkcompiler/ets_frontend/merge_abc" \ + " --ark-frontend=es2panda" + return cmd + @staticmethod - def get_test262_baseline_jit_cmd(gn_args, out_path, x64_out_path, args_to_test262_cmd, timeout): - print("running test262 in baseline JIT mode\n") + def get_baseline_jit_cmd(test_suite, test_script_name, test_script_path, gn_args, out_path, x64_out_path, + args_to_test262_cmd, timeout): + print(f"running {test_suite} in baseline JIT mode\n") if any('target_cpu="arm64"' in arg for arg in gn_args): - test262_cmd = "cd arkcompiler/ets_frontend && python3 test262/run_test262.py {0} --timeout {3}" \ - " --libs-dir ../../prebuilts/clang/ohos/linux-x86_64/llvm/lib" \ - ":../../{1}/thirdparty/icu" \ - ":../../prebuilts/clang/ohos/linux-x86_64/llvm/lib/aarch64-linux-ohos" \ - ":../../{1}/thirdparty/bounds_checking_function" \ - ":../../{1}/arkcompiler/ets_runtime" \ - ":../../{1}/common/common/libc/lib" \ - " --ark-arch aarch64" \ - " --run-baseline-jit" \ - " --ark-arch-root=../../{1}/common/common/libc/" \ - " --ark-aot-tool=../../{2}/arkcompiler/ets_runtime/ark_aot_compiler" \ - " --ark-tool=../../{1}/arkcompiler/ets_runtime/ark_js_vm" \ - " --ark-frontend-binary=../../{2}/arkcompiler/ets_frontend/es2abc" \ - " --merge-abc-binary=../../{2}/arkcompiler/ets_frontend/merge_abc" \ - " --ark-frontend=es2panda".format(args_to_test262_cmd, out_path, x64_out_path, timeout) + cmd = f"cd {test_script_path} && python3 {test_script_name} {args_to_test262_cmd} --timeout {timeout}" \ + f" --libs-dir ../../prebuilts/clang/ohos/linux-x86_64/llvm/lib" \ + f":../../{out_path}/thirdparty/icu" \ + f":../../prebuilts/clang/ohos/linux-x86_64/llvm/lib/aarch64-linux-ohos" \ + f":../../{out_path}/thirdparty/bounds_checking_function" \ + f":../../{out_path}/arkcompiler/ets_runtime" \ + f":../../{out_path}/common/common/libc/lib" \ + " --ark-arch aarch64" \ + " --run-baseline-jit" \ + f" --ark-arch-root=../../{out_path}/common/common/libc/" \ + f" --ark-aot-tool=../../{x64_out_path}/arkcompiler/ets_runtime/ark_aot_compiler" \ + f" --ark-tool=../../{out_path}/arkcompiler/ets_runtime/ark_js_vm" \ + f" --ark-frontend-binary=../../{x64_out_path}/arkcompiler/ets_frontend/es2abc" \ + f" --merge-abc-binary=../../{x64_out_path}/arkcompiler/ets_frontend/merge_abc" \ + " --ark-frontend=es2panda" else: - test262_cmd = "cd arkcompiler/ets_frontend && python3 test262/run_test262.py {0} --timeout {3}" \ - " --libs-dir ../../{1}/lib.unstripped/arkcompiler/ets_runtime" \ - ":../../{1}/lib.unstripped/thirdparty/icu" \ - ":../../prebuilts/clang/ohos/linux-x86_64/llvm/lib" \ - ":../../{1}/lib.unstripped/thirdparty/bounds_checking_function/" \ - " --run-baseline-jit" \ - " --ark-tool=../../{1}/arkcompiler/ets_runtime/ark_js_vm" \ - " --ark-frontend-binary=../../{1}/arkcompiler/ets_frontend/es2abc" \ - " --merge-abc-binary=../../{1}/arkcompiler/ets_frontend/merge_abc" \ - " --ark-frontend=es2panda"\ - "{2}".format(args_to_test262_cmd, out_path, x64_out_path, timeout) - return test262_cmd + cmd = f"cd {test_script_path} && python3 {test_script_name} {args_to_test262_cmd} --timeout {timeout}" \ + f" --libs-dir ../../{out_path}/lib.unstripped/arkcompiler/ets_runtime" \ + f":../../{out_path}/thirdparty/icu" \ + ":../../prebuilts/clang/ohos/linux-x86_64/llvm/lib" \ + f":../../{out_path}/thirdparty/bounds_checking_function/" \ + " --run-baseline-jit" \ + f" --ark-tool=../../{out_path}/arkcompiler/ets_runtime/ark_js_vm" \ + f" --ark-frontend-binary=../../{out_path}/arkcompiler/ets_frontend/es2abc" \ + f" --merge-abc-binary=../../{out_path}/arkcompiler/ets_frontend/merge_abc" \ + " --ark-frontend=es2panda" + return cmd @staticmethod def build_args_to_test262_cmd(arg_list): args_to_test262_cmd = [] - disable_force_gc = [arg for arg in arg_list if "disable-force-gc" in arg] - if disable_force_gc: - args_to_test262_cmd.append("--disable-force-gc") - arg_list.remove(disable_force_gc[0]) + disable_force_gc_name = "--disable-force-gc" + disable_force_gc_value, arg_list = ArkPy.parse_bool_option( + arg_list, option_name=disable_force_gc_name, default_value=False + ) + if disable_force_gc_value: + args_to_test262_cmd.extend([disable_force_gc_name]) threads_name = "--threads" threads_value, arg_list = ArkPy.parse_option(arg_list, option_name=threads_name, default_value=None) if threads_value: args_to_test262_cmd.extend([threads_name, threads_value]) + test_list_name = "--test-list" + test_list_value, arg_list = ArkPy.parse_option(arg_list, option_name=test_list_name, default_value=None) + if test_list_value is not None: + args_to_test262_cmd.extend([test_list_name, test_list_value]) + + enable_rm = [arg for arg in arg_list if "enable-rm" in arg] + if enable_rm: + args_to_test262_cmd.append("--enable-rm") + arg_list.remove(enable_rm[0]) + + skip_list_name = "--skip-list" + skip_list_value, arg_list = ArkPy.parse_option(arg_list, option_name=skip_list_name, default_value=None) + if skip_list_value is not None: + args_to_test262_cmd.extend([skip_list_name, skip_list_value]) + if len(arg_list) == 0: args_to_test262_cmd.append("--es2021 all") elif len(arg_list) == 1: arg = arg_list[0] - if ".js" in arg: + if arg == "sendable": + args_to_test262_cmd.append("--sendable sendable") + elif ".js" in arg: args_to_test262_cmd.append("--file test262/data/test_es2021/{}".format(arg)) else: args_to_test262_cmd.append("--dir test262/data/test_es2021/{}".format(arg)) @@ -469,6 +543,13 @@ class ArkPy: def build_args_to_regress_cmd(arg_list): args_to_regress_cmd = [] + disable_force_gc_name = "--disable-force-gc" + disable_force_gc_value, arg_list = ArkPy.parse_bool_option( + arg_list, option_name=disable_force_gc_name, default_value=False + ) + if disable_force_gc_value: + args_to_regress_cmd.extend([disable_force_gc_name]) + processes_name = "--processes" processes_value, arg_list = ArkPy.parse_option(arg_list, option_name=processes_name, default_value=1) args_to_regress_cmd.extend([processes_name, processes_value]) @@ -500,6 +581,18 @@ class ArkPy: option_value = default_value return option_value, arg_list + @staticmethod + def parse_bool_option(arg_list: List[str], option_name: str, default_value: bool) \ + -> Tuple[bool, List[str]]: + if option_name in arg_list: + option_index = arg_list.index(option_name) + option_value = not default_value + arg_list = arg_list[:option_index] + arg_list[option_index + 1:] + else: + option_value = default_value + + return option_value, arg_list + @staticmethod def __is_option_value_int(value: Optional[Union[str, int]]) -> Tuple[bool, Optional[int]]: if isinstance(value, int): @@ -556,6 +649,16 @@ class ArkPy: sys.exit(1) return None, arg_list + @staticmethod + def __get_x64_out_path(out_path) -> str: + if 'release' in out_path: + return 'out/x64.release' + if 'debug' in out_path: + return 'out/x64.debug' + if 'fastverify' in out_path: + return 'out/x64.fastverify' + return "" + def get_binaries(self): host_os = sys.platform host_cpu = platform.machine() @@ -572,18 +675,18 @@ class ArkPy: print("\nLogic of getting gn binary or ninja binary does not match logic of prebuilts_download." \ "\nCheck func \033[92m{0} of class {1} in file {2}\033[0m against file {3} if the name of this " \ "file had not changed!\n".format( - sys._getframe().f_code.co_name, self.__class__.__name__, CURRENT_FILENAME, - self.PREBUILTS_DOWNLOAD_CONFIG_FILE_PATH)) + sys._getframe().f_code.co_name, self.__class__.__name__, CURRENT_FILENAME, + self.PREBUILTS_DOWNLOAD_CONFIG_FILE_PATH)) raise error if self.gn_binary_path == "" or self.ninja_binary_path == "": print("\nLogic of prebuilts_download may be wrong." \ "\nCheck \033[92mdata in file {0}\033[0m against func {1} of class {2} in file {3}!\n".format( - self.PREBUILTS_DOWNLOAD_CONFIG_FILE_PATH, sys._getframe().f_code.co_name, self.__class__.__name__, - CURRENT_FILENAME)) + self.PREBUILTS_DOWNLOAD_CONFIG_FILE_PATH, sys._getframe().f_code.co_name, self.__class__.__name__, + CURRENT_FILENAME)) sys.exit(0) if not os.path.isfile(self.gn_binary_path) or not os.path.isfile(self.ninja_binary_path): print("\nStep for prebuilts_download may be ommited. (\033[92m./prebuilts_download.sh\033[0m)" \ - "\nCheck \033[92mwhether gn binary and ninja binary are under directory prebuilts\033[0m!\n".format()) + "\nCheck \033[92mwhether gn binary and ninja binary are under directory prebuilts\033[0m!\n".format()) sys.exit(0) return @@ -603,13 +706,13 @@ class ArkPy: if len(arg_to_list) == 1: os_cpu_part = arg_to_list[0] mode_part = "release" - key_to_dict_in_os_cpu_matched_arg = self.which_dict_flags_match_arg(self.ARG_DICT["os_cpu"], os_cpu_part) - key_to_dict_in_mode_matched_arg = self.which_dict_flags_match_arg(self.ARG_DICT["mode"], mode_part) + key_to_dict_in_os_cpu_matched_arg = self.which_dict_flags_match_arg(self.ARG_DICT.get("os_cpu"), os_cpu_part) + key_to_dict_in_mode_matched_arg = self.which_dict_flags_match_arg(self.ARG_DICT.get("mode"), mode_part) elif len(arg_to_list) == 2: os_cpu_part = arg_to_list[0] mode_part = arg_to_list[1] - key_to_dict_in_os_cpu_matched_arg = self.which_dict_flags_match_arg(self.ARG_DICT["os_cpu"], os_cpu_part) - key_to_dict_in_mode_matched_arg = self.which_dict_flags_match_arg(self.ARG_DICT["mode"], mode_part) + key_to_dict_in_os_cpu_matched_arg = self.which_dict_flags_match_arg(self.ARG_DICT.get("os_cpu"), os_cpu_part) + key_to_dict_in_mode_matched_arg = self.which_dict_flags_match_arg(self.ARG_DICT.get("mode"), mode_part) else: print("\"\033[92m{0}\033[0m\" combined with more than 2 flags is not supported.".format(arg)) if (key_to_dict_in_os_cpu_matched_arg == "") | (key_to_dict_in_mode_matched_arg == ""): @@ -635,9 +738,10 @@ class ArkPy: help_msg += "\033[32mCommand template:\033[0m\n{}\n\n".format( " python3 ark.py \033[92m[os_cpu].[mode] [gn_target] [option]\033[0m\n" " python3 ark.py \033[92m[os_cpu].[mode] [test262] [none or --aot] " \ - "[none or --pgo] [none or --litecg] [none, file or dir] [none or --threads=X] [option]\033[0m\n" + "[none or --pgo] [none or --litecg] [none, file or dir] [none or --threads=X] [option]\033[0m\n" " python3 ark.py \033[92m[os_cpu].[mode] [test262] [none or --jit] [none or --threads=X]\033[0m\n" - " python3 ark.py \033[92m[os_cpu].[mode] [test262] [none or --baseline-jit] [none or --threads=X]\033[0m\n" + " python3 ark.py \033[92m[os_cpu].[mode] [test262] [none or --baseline-jit] [none or --enable-rm] " \ + "[none or --threads=X and/or --test-list TEST_LIST_NAME]\033[0m\n" " python3 ark.py \033[92m[os_cpu].[mode] [unittest] [option]\033[0m\n" " python3 ark.py \033[92m[os_cpu].[mode] [regresstest] [none, file or dir] " \ "[none or --processes X and/or --test-list TEST_LIST_NAME]\033[0m\n") @@ -651,7 +755,7 @@ class ArkPy: " python3 ark.py \033[92mx64.release test262 --threads=16\033[0m\n" " python3 ark.py \033[92mx64.release test262 --aot --pgo --litecg\033[0m\n" " python3 ark.py \033[92mx64.release test262 --aot --pgo --litecg --threads=8\033[0m\n" - " python3 ark.py \033[92mx64.release test262 --jit\033[0m\n" + " python3 ark.py \033[92mx64.release test262 --jit --enable-rm\033[0m\n" " python3 ark.py \033[92mx64.release test262 --baseline-jit\033[0m\n" " python3 ark.py \033[92mx64.release test262 built-ins/Array\033[0m\n" " python3 ark.py \033[92mx64.release test262 built-ins/Array/name.js\033[0m\n" @@ -686,13 +790,18 @@ class ArkPy: # prepare log file build_log_path = os.path.join(out_path, log_file_name) backup(build_log_path, "w") + if arg_list is not None: + build_target = " ".join([str(arg).strip() for arg in arg_list + if arg is not None or len(str(arg).strip()) > 0]) + else: + build_target = "" str_to_build_log = "================================\nbuild_time: {0}\nbuild_target: {1}\n\n".format( - str_of_time_now(), " ".join(arg_list)) + str_of_time_now(), build_target) _write(build_log_path, str_to_build_log, "a") # gn command print("=== gn gen start ===") code = call_with_output( - "{0} gen {1} --args=\"{2}\"".format( + "{0} gen {1} --args=\"{2}\" --export-compile-commands".format( self.gn_binary_path, out_path, " ".join(gn_args).replace("\"", "\\\"")), build_log_path) if code != 0: @@ -704,13 +813,13 @@ class ArkPy: # Always add " -d keeprsp" to ninja command to keep response file("*.rsp"), thus we could get shared libraries # of an excutable from its response file. ninja_cmd = \ - self.ninja_binary_path + \ - (" -v" if self.enable_verbose else "") + \ - (" -d keepdepfile" if self.enable_keepdepfile else "") + \ - " -d keeprsp" + \ - " -C {}".format(out_path) + \ - " {}".format(" ".join(arg_list)) + \ - " -k {}".format(self.ignore_errors) + self.ninja_binary_path + \ + (" -v" if self.enable_verbose else "") + \ + (" -d keepdepfile" if self.enable_keepdepfile else "") + \ + " -d keeprsp" + \ + " -C {}".format(out_path) + \ + " {}".format(" ".join(arg_list if arg_list else [])) + \ + " -k {}".format(self.ignore_errors) print(ninja_cmd) code = call_with_output(ninja_cmd, build_log_path) if code != 0: @@ -720,77 +829,141 @@ class ArkPy: print("=== ninja success! ===\n") return - def build_for_test262(self, out_path, timeout, gn_args: list, arg_list: list, log_file_name: str, - aot_mode: bool, run_pgo=False, enable_litecg=False, run_jit=False, - run_baseline_jit=False): - args_to_test262_cmd = self.build_args_to_test262_cmd(arg_list) - x64_out_path = "" + def call_build_gn_target(self, gn_args, out_path, x64_out_path, test_suite, log_file_name): if any('target_cpu="arm64"' in arg for arg in gn_args): - if 'release' in out_path: - x64_out_path = 'out/x64.release' - if 'debug' in out_path: - x64_out_path = 'out/x64.debug' gn_args.append("so_dir_for_qemu=\"../../{0}/common/common/libc/\"".format(out_path)) gn_args.append("run_with_qemu=true".format(out_path)) if not os.path.exists(x64_out_path): os.makedirs(x64_out_path) self.build_for_gn_target( - x64_out_path, ['target_os="linux"', 'target_cpu="x64"', 'is_debug=false'], - self.ARG_DICT["target"]["test262"]["gn_targets_depend_on"], log_file_name) + x64_out_path, + ['target_os="linux"', 'target_cpu="x64"', 'is_debug=false'], + self.ARG_DICT.get("target").get(test_suite).get("gn_targets_depend_on"), + log_file_name) self.build_for_gn_target( - out_path, gn_args, self.ARG_DICT["target"]["test262"]["arm64_gn_targets_depend_on"], log_file_name) + out_path, + gn_args, + self.ARG_DICT.get("target").get(test_suite).get("arm64_gn_targets_depend_on"), + log_file_name) else: self.build_for_gn_target( - out_path, gn_args, self.ARG_DICT["target"]["test262"]["gn_targets_depend_on"], log_file_name) + out_path, + gn_args, + self.ARG_DICT.get("target").get(test_suite).get("gn_targets_depend_on"), + log_file_name) + + def get_build_cmd(self, *, test_suite, test_script_name, test_script_path, + out_path, x64_out_path, gn_args: list, args_to_cmd: str, timeout, + run_jit: bool = False, run_baseline_jit: bool = False, aot_mode: bool = False, + run_pgo: bool = False, enable_litecg: bool = False, ignore_list: Optional[str] = None) -> str: if run_jit: - test262_cmd = self.get_test262_jit_cmd(gn_args, out_path, x64_out_path, args_to_test262_cmd, timeout) + cmd = self.get_jit_cmd(test_suite, test_script_name, test_script_path, + gn_args, out_path, x64_out_path, args_to_cmd, timeout) elif run_baseline_jit: - test262_cmd = self.get_test262_baseline_jit_cmd(gn_args, out_path, x64_out_path, - args_to_test262_cmd, timeout) - elif aot_mode: - test262_cmd = self.get_test262_aot_cmd(gn_args, out_path, x64_out_path, run_pgo, enable_litecg, args_to_test262_cmd, - timeout) + cmd = self.get_baseline_jit_cmd(test_suite, test_script_name, test_script_path, + gn_args, out_path, x64_out_path, args_to_cmd, timeout) + elif aot_mode and test_suite == "test262": + cmd = self.get_test262_aot_cmd(gn_args, out_path, x64_out_path, run_pgo, + enable_litecg, args_to_cmd, timeout) else: - test262_cmd = self.get_test262_cmd(gn_args, out_path, x64_out_path, run_pgo, - enable_litecg, args_to_test262_cmd, timeout) - test262_log_path = os.path.join(out_path, log_file_name) - str_to_test262_log = "================================\ntest262_time: {0}\ntest262_target: {1}\n\n".format( - str_of_time_now(), args_to_test262_cmd) - _write(test262_log_path, str_to_test262_log, "a") - print("=== test262 start ===") - code = call_with_output(test262_cmd, test262_log_path) + cmd = self.get_cmd(test_suite, test_script_name, test_script_path, + gn_args, out_path, x64_out_path, aot_mode, run_pgo, + enable_litecg, args_to_cmd, timeout, ignore_list) + return cmd + + def build_for_suite(self, *, test_suite, test_script_name, test_script_path, + out_path, gn_args: list, log_file_name, args_to_cmd: str, timeout, + run_jit: bool = False, run_baseline_jit: bool = False, aot_mode: bool = False, + run_pgo: bool = False, enable_litecg: bool = False, ignore_list: Optional[str] = None): + x64_out_path = self.__get_x64_out_path(out_path) + self.call_build_gn_target(gn_args, out_path, x64_out_path, test_suite, log_file_name) + cmd = self.get_build_cmd( + test_suite=test_suite, + test_script_name=test_script_name, + test_script_path=test_script_path, + out_path=out_path, + x64_out_path=x64_out_path, + gn_args=gn_args, + args_to_cmd=args_to_cmd, + timeout=timeout, + run_jit=run_jit, + run_baseline_jit=run_baseline_jit, + aot_mode=aot_mode, run_pgo=run_pgo, enable_litecg=enable_litecg, ignore_list=ignore_list) + log_path = str(os.path.join(out_path, log_file_name)) + str_to_log = "================================\n{2}_time: {0}\n{2}_target: {1}\n\n".format( + str_of_time_now(), args_to_cmd, test_suite) + _write(log_path, str_to_log, "a") + print(f"=== {test_suite} start ===") + code = call_with_output(cmd, log_path) if code != 0: - print("=== test262 fail! ===\n") + print(f"=== {test_suite} fail! ===\n") sys.exit(code) - print("=== test262 success! ===\n") + print(f"=== {test_suite} success! ===\n") + + def build_for_test262(self, out_path, gn_args: list, arg_list: list): + timeout, arg_list = self.parse_timeout(arg_list) + arg_list = arg_list[1:] + + is_aot_mode, arg_list = self.__purge_arg_list("--aot", arg_list) + is_pgo, arg_list = self.__purge_arg_list("--pgo", arg_list) + is_litecg, arg_list = self.__purge_arg_list("--litecg", arg_list) + is_jit, arg_list = self.__purge_arg_list("--jit", arg_list) + is_baseline_jit, arg_list = self.__purge_arg_list("--baseline-jit", arg_list) + print(f"Test262: arg_list = {arg_list}") - def build_for_unittest(self, out_path: str, gn_args: list, log_file_name:str): + args_to_test262_cmd = self.build_args_to_test262_cmd(arg_list) + self.build_for_suite( + test_suite="test262", + test_script_name="test262/run_test262.py", + test_script_path="arkcompiler/ets_frontend", + out_path=out_path, + gn_args=gn_args, + log_file_name=self.TEST262_LOG_FILE_NAME, + args_to_cmd=args_to_test262_cmd, + timeout=timeout, + run_jit=is_jit, + run_pgo=is_pgo, + run_baseline_jit=is_baseline_jit, + aot_mode=is_aot_mode, + enable_litecg=is_litecg + ) + + def build_for_unittest(self, out_path: str, gn_args: list, log_file_name: str): self.build_for_gn_target( - out_path, gn_args, self.ARG_DICT["target"]["unittest"]["gn_targets_depend_on"], + out_path, gn_args, self.ARG_DICT.get("target").get("unittest").get("gn_targets_depend_on"), log_file_name) return - def build_for_regress_test(self, out_path, gn_args: list, arg_list: list, log_file_name: str, timeout): + def build_for_regress_test(self, out_path, gn_args: list, arg_list: list): + timeout, arg_list = self.parse_option(arg_list, option_name="--timeout", default_value=200) + ignore_list, arg_list = self.parse_option(arg_list, option_name="--ignore-list", default_value=None) + + arg_list = arg_list[1:] + + is_aot, arg_list = self.__purge_arg_list("--aot", arg_list) + is_pgo, arg_list = self.__purge_arg_list("--pgo", arg_list) + is_litecg, arg_list = self.__purge_arg_list("--litecg", arg_list) + is_jit, arg_list = self.__purge_arg_list("--jit", arg_list) + is_baseline_jit, arg_list = self.__purge_arg_list("--baseline-jit", arg_list) + print(f"Regress: arg_list = {arg_list}") + args_to_regress_test_cmd = self.build_args_to_regress_cmd(arg_list) - self.build_for_gn_target( - out_path, gn_args, self.ARG_DICT["target"]["regresstest"]["gn_targets_depend_on"], log_file_name) - regress_test_cmd = "python3 arkcompiler/ets_runtime/test/regresstest/run_regress_test.py --timeout {2}" \ - " --ark-tool ./{0}/arkcompiler/ets_runtime/ark_js_vm" \ - " --ark-frontend-binary ./{0}/arkcompiler/ets_frontend/es2abc" \ - " --LD_LIBRARY_PATH ./{0}/arkcompiler/ets_runtime:./{0}/thirdparty/icu:" \ - "./prebuilts/clang/ohos/linux-x86_64/llvm/lib" \ - " --out-dir ./{0}/ {1}".format(out_path, args_to_regress_test_cmd, timeout) - regress_test_log_path = os.path.join(out_path, log_file_name) - str_to_test_log = "============\n regresstest_time: {0}\nregresstest_target: {1}\n\n".format( - str_of_time_now(), regress_test_cmd) - _write(regress_test_log_path, str_to_test_log, "a") - print("=== regresstest start ===") - code = call_with_output(regress_test_cmd, regress_test_log_path) - if code != 0: - print("=== regresstest fail! ===\n") - sys.exit(code) - print("=== regresstest success! ===\n") - return + self.build_for_suite( + test_suite="regresstest", + test_script_name="test/regresstest/run_regress_test.py", + test_script_path="arkcompiler/ets_runtime", + out_path=out_path, + gn_args=gn_args, + log_file_name=self.REGRESS_TEST_LOG_FILE_NAME, + args_to_cmd=args_to_regress_test_cmd, + timeout=timeout, + run_jit=is_jit, + run_pgo=is_pgo, + run_baseline_jit=is_baseline_jit, + aot_mode=is_aot, + enable_litecg=is_litecg, + ignore_list=ignore_list + ) def build(self, out_path: str, gn_args: list, arg_list: list): if not os.path.exists(out_path): @@ -798,47 +971,17 @@ class ArkPy: os.makedirs(out_path) if len(arg_list) == 0: self.build_for_gn_target(out_path, gn_args, ["default"], self.GN_TARGET_LOG_FILE_NAME) - elif self.is_dict_flags_match_arg(self.ARG_DICT["target"]["workload"], arg_list[0]): + elif self.is_dict_flags_match_arg(self.ARG_DICT.get("target").get("workload"), arg_list[0]): self.build_for_workload(arg_list, out_path, gn_args, 'workload.log') - elif self.is_dict_flags_match_arg(self.ARG_DICT["target"]["test262"], arg_list[0]): - timeout, arg_list = self.parse_timeout(arg_list) - run_aot_mode = len(arg_list) >= 2 and arg_list[1] == "--aot" - run_aot_pgo_litecg = len(arg_list) >= 4 and ((arg_list[2] == "--pgo" and arg_list[3] == "--litecg") or - (arg_list[3] == "--pgo" and arg_list[2] == "--litecg")) - run_aot_pgo = len(arg_list) >= 3 and arg_list[2] == "--pgo" - run_aot_litecg = len(arg_list) >= 3 and arg_list[2] == "--litecg" - run_jit = len(arg_list) >= 2 and arg_list[1] == "--jit" - run_baseline_jit = len(arg_list) >= 2 and arg_list[1] == "--baseline-jit" - if run_aot_mode: - if run_aot_pgo_litecg: - self.build_for_test262(out_path, timeout, gn_args, arg_list[4:], self.TEST262_LOG_FILE_NAME, True, - True, True) - elif run_aot_litecg: - self.build_for_test262(out_path, timeout, gn_args, arg_list[3:], self.TEST262_LOG_FILE_NAME, True, - False, True) - elif run_aot_pgo: - self.build_for_test262(out_path, timeout, gn_args, arg_list[3:], - self.TEST262_LOG_FILE_NAME, True, True) - else: - self.build_for_test262(out_path, timeout, gn_args, arg_list[2:], self.TEST262_LOG_FILE_NAME, True) - elif run_jit: - self.build_for_test262(out_path, timeout, gn_args, arg_list[2:], - self.TEST262_LOG_FILE_NAME, False, False, - False, True) - elif run_baseline_jit: - self.build_for_test262(out_path, timeout, gn_args, arg_list[2:], - self.TEST262_LOG_FILE_NAME, False, False, - False, False, True) - else: - self.build_for_test262(out_path, timeout, gn_args, arg_list[1:], self.TEST262_LOG_FILE_NAME, False) - elif self.is_dict_flags_match_arg(self.ARG_DICT["target"]["unittest"], arg_list[0]): + elif self.is_dict_flags_match_arg(self.ARG_DICT.get("target").get("test262"), arg_list[0]): + self.build_for_test262(out_path, gn_args, arg_list) + elif self.is_dict_flags_match_arg(self.ARG_DICT.get("target").get("unittest"), arg_list[0]): if len(arg_list) > 1: print("\033[92m\"unittest\" not support additional arguments.\033[0m\n".format()) sys.exit(0) self.build_for_unittest(out_path, gn_args, self.UNITTEST_LOG_FILE_NAME) - elif self.is_dict_flags_match_arg(self.ARG_DICT["target"]["regresstest"], arg_list[0]): - timeout, arg_list = self.parse_option(arg_list, option_name="--timeout", default_value=200) - self.build_for_regress_test(out_path, gn_args, arg_list[1:], self.REGRESS_TEST_LOG_FILE_NAME, timeout) + elif self.is_dict_flags_match_arg(self.ARG_DICT.get("target").get("regresstest"), arg_list[0]): + self.build_for_regress_test(out_path, gn_args, arg_list) else: self.build_for_gn_target(out_path, gn_args, arg_list, self.GN_TARGET_LOG_FILE_NAME) return @@ -851,27 +994,27 @@ class ArkPy: gn_args_ret = [] for arg in arg_list: # match [option][clean] flag - if self.is_dict_flags_match_arg(self.ARG_DICT["option"]["clean"], arg): + if self.is_dict_flags_match_arg(self.ARG_DICT.get("option").get("clean"), arg): self.clean(out_path) sys.exit(0) # match [option][clean-continue] flag - elif self.is_dict_flags_match_arg(self.ARG_DICT["option"]["clean-continue"], arg): + elif self.is_dict_flags_match_arg(self.ARG_DICT.get("option").get("clean-continue"), arg): if not self.has_cleaned: self.clean(out_path) self.has_cleaned = True # match [option][gn-args] flag - elif self.is_dict_flags_match_arg(self.ARG_DICT["option"]["gn-args"], arg): + elif self.is_dict_flags_match_arg(self.ARG_DICT.get("option").get("gn-args"), arg): gn_args_ret.append(arg[(arg.find("=") + 1):]) # match [option][keepdepfile] flag - elif self.is_dict_flags_match_arg(self.ARG_DICT["option"]["keepdepfile"], arg): + elif self.is_dict_flags_match_arg(self.ARG_DICT.get("option").get("keepdepfile"), arg): if not self.enable_keepdepfile: self.enable_keepdepfile = True # match [option][verbose] flag - elif self.is_dict_flags_match_arg(self.ARG_DICT["option"]["verbose"], arg): + elif self.is_dict_flags_match_arg(self.ARG_DICT.get("option").get("verbose"), arg): if not self.enable_verbose: self.enable_verbose = True # match [option][keep-going] flag - elif self.is_dict_flags_match_arg(self.ARG_DICT["option"]["keep-going"], arg): + elif self.is_dict_flags_match_arg(self.ARG_DICT.get("option").get("keep-going"), arg): if self.ignore_errors == 1: input_value = arg[(arg.find("=") + 1):] try: @@ -908,13 +1051,13 @@ class ArkPy: run_interpreter = True self.build_for_gn_target(out_path, gn_args, ["default"], self.GN_TARGET_LOG_FILE_NAME) workload_cmd = "cd arkcompiler/ets_runtime/test/workloadtest/ && python3 work_load.py" \ - " --code-path {0}" \ - " --report {1}" \ - " --tools-type {2}" \ - " --boundary-value {3}" \ - " --run-count {4}" \ - " --code-v {5}" \ - .format(root_dir, report, tools, boundary_value, run_count, code_v) + " --code-path {0}" \ + " --report {1}" \ + " --tools-type {2}" \ + " --boundary-value {3}" \ + " --run-count {4}" \ + " --code-v {5}" \ + .format(root_dir, report, tools, boundary_value, run_count, code_v) if run_interpreter: workload_cmd += " --run-interpreter true" workload_log_path = os.path.join(out_path, log_file_name) @@ -934,19 +1077,24 @@ class ArkPy: self.get_binaries() # get out_path name_of_out_dir_of_second_level = \ - self.ARG_DICT["os_cpu"][os_cpu_key]["prefix_of_name_of_out_dir_of_second_level"] + \ + self.ARG_DICT.get("os_cpu").get(os_cpu_key).get("prefix_of_name_of_out_dir_of_second_level") + \ self.DELIMITER_FOR_SECOND_OUT_DIR_NAME + \ - self.ARG_DICT["mode"][mode_key]["suffix_of_name_of_out_dir_of_second_level"] + self.ARG_DICT.get("mode").get(mode_key).get("suffix_of_name_of_out_dir_of_second_level") out_path = os.path.join(self.NAME_OF_OUT_DIR_OF_FIRST_LEVEL, name_of_out_dir_of_second_level) # match [option] flag [arg_list, gn_args] = self.match_options(arg_list, out_path) # get expression which would be written to args.gn file - gn_args.extend(self.ARG_DICT["os_cpu"][os_cpu_key]["gn_args"]) - gn_args.extend(self.ARG_DICT["mode"][mode_key]["gn_args"]) + gn_args.extend(self.ARG_DICT.get("os_cpu").get(os_cpu_key).get("gn_args")) + gn_args.extend(self.ARG_DICT.get("mode").get(mode_key).get("gn_args")) # start to build self.build(out_path, gn_args, arg_list) return + def __purge_arg_list(self, option_name: str, arg_list: List[Any]) -> Tuple[bool, List[Any]]: + if option_name in arg_list: + arg_list.remove(option_name) + return True, arg_list + return False, arg_list if __name__ == "__main__": diff --git a/build/config/compiler/BUILD.gn b/build/config/compiler/BUILD.gn index 4613b124033505670bea4e2ac0a0b0479efb0358..1478110c1e05b0cbc0681f7a4ee94af8374c2183 100644 --- a/build/config/compiler/BUILD.gn +++ b/build/config/compiler/BUILD.gn @@ -32,6 +32,19 @@ config("rtti") { } } +config("no_exceptions") { + if (is_linux) { + cflags_cc = [ "-fno-exceptions" ] + cflags_objcc = cflags_cc + } +} + +config("optimize_speed") { + if (is_linux) { + cflags_cc = [ "-O3" ] + } +} + config("no_rtti") { # Some sanitizer configs may require RTTI to be left enabled globally if (!use_rtti) { diff --git a/build/core/gn/BUILD.gn b/build/core/gn/BUILD.gn index c9ff832cb070efd8d0991a472addbaf0e04da5e0..5483815961175acc7ce9e56ae09b356390283331 100644 --- a/build/core/gn/BUILD.gn +++ b/build/core/gn/BUILD.gn @@ -76,6 +76,15 @@ group("runtime_core") { ] } +group("static_core") { + deps = [ + "$ark_root/static_core/assembler:libarktsassembler", + "$ark_root/static_core/bytecode_optimizer:libarktsbytecodeopt", + "$ark_root/static_core/libpandabase:libarktsbase", + "$ark_root/static_core/libpandafile:libarktsfile", + ] +} + group("toolchain") { deps = [] if (target_cpu != "mipsel") { diff --git a/build/prebuilts_download/prebuilts_download.py b/build/prebuilts_download/prebuilts_download.py index c62d8e2dadd67e39694cbc7a108bb85ef587549a..74815dfd6b1a46db2580591a76818393a5138135 100755 --- a/build/prebuilts_download/prebuilts_download.py +++ b/build/prebuilts_download/prebuilts_download.py @@ -152,6 +152,10 @@ def _hwcloud_download(args, config, bin_dir, code_dir, retries): _run_cmd(''.join(['rm -rf ', code_dir, '/', unzip_dir, '/*.', unzip_filename, '.mark'])) _run_cmd(''.join(['rm -rf ', code_dir, '/', unzip_dir, '/', unzip_filename])) local_file = os.path.join(bin_dir, ''.join([md5_huaweicloud_url, '.', bin_file])) + + if os.path.exists(local_file) and not _check_sha256(huaweicloud_url, local_file): + os.remove(local_file) + if not os.path.exists(local_file): filename = huaweicloud_url.split("/")[-1] task_id = progress.add_task("download", filename=filename, start=False) diff --git a/build/test.gni b/build/test.gni index 499f070a6a5d23b7af6bbe704cf21f901e72bbaa..85e6055279894f4e1fb50c3094ffd82ad478b89f 100644 --- a/build/test.gni +++ b/build/test.gni @@ -75,7 +75,14 @@ template("ohos_unittest") { deps += invoker.deps } - deps += - [ "//arkcompiler/toolchain/build/third_party_gn/googletest:gtest_main" ] + # Add static link library judgment logic below + + if (defined(invoker.rtti_compile_flag) && invoker.rtti_compile_flag) { + deps += [ "//arkcompiler/toolchain/build/third_party_gn/googletest:gtest_rtti_main" ] + } else { + deps += [ + "//arkcompiler/toolchain/build/third_party_gn/googletest:gtest_main", + ] + } } } diff --git a/build/third_party_gn/googletest/BUILD.gn b/build/third_party_gn/googletest/BUILD.gn index 051465049606ed9c5cdb06ba780e37f43cc166b5..9aeba8c7ec0c4c6e5755866425f69ed00cdb5109 100644 --- a/build/third_party_gn/googletest/BUILD.gn +++ b/build/third_party_gn/googletest/BUILD.gn @@ -19,8 +19,22 @@ config("gtest_private_config") { include_dirs = [ "$googletest_dir" ] } +config("gtest_private_config_rtti") { + visibility = [ ":*" ] + include_dirs = [ "$googletest_dir" ] + cflags = [ "-frtti" ] + cflags_objcc = [ "-frtti" ] + cflags_cc = [ "-frtti" ] +} + config("gtest_config") { include_dirs = [ "$googletest_dir/include" ] + cflags_cc = [ + "-std=c++17", + "-Wno-float-equal", + "-Wno-sign-compare", + "-Wno-reorder-init-list", + ] if (is_mingw) { cflags_cc = [ "-Wno-unused-const-variable", @@ -29,57 +43,80 @@ config("gtest_config") { } } +sources_files = [ + "$googletest_dir/include/gtest/gtest-death-test.h", + "$googletest_dir/include/gtest/gtest-matchers.h", + "$googletest_dir/include/gtest/gtest-message.h", + "$googletest_dir/include/gtest/gtest-param-test.h", + "$googletest_dir/include/gtest/gtest-printers.h", + "$googletest_dir/include/gtest/gtest-test-part.h", + "$googletest_dir/include/gtest/gtest-typed-test.h", + "$googletest_dir/include/gtest/gtest_pred_impl.h", + "$googletest_dir/include/gtest/gtest_prod.h", + "$googletest_dir/include/gtest/hwext/gtest-ext.h", + "$googletest_dir/include/gtest/hwext/gtest-filter.h", + "$googletest_dir/include/gtest/hwext/gtest-multithread.h", + "$googletest_dir/include/gtest/hwext/gtest-tag.h", + "$googletest_dir/include/gtest/hwext/utils.h", + "$googletest_dir/include/gtest/internal/custom/gtest-port.h", + "$googletest_dir/include/gtest/internal/custom/gtest-printers.h", + "$googletest_dir/include/gtest/internal/custom/gtest.h", + "$googletest_dir/include/gtest/internal/gtest-death-test-internal.h", + "$googletest_dir/include/gtest/internal/gtest-filepath.h", + "$googletest_dir/include/gtest/internal/gtest-internal.h", + "$googletest_dir/include/gtest/internal/gtest-param-util.h", + "$googletest_dir/include/gtest/internal/gtest-port-arch.h", + "$googletest_dir/include/gtest/internal/gtest-port.h", + "$googletest_dir/include/gtest/internal/gtest-string.h", + "$googletest_dir/include/gtest/internal/gtest-type-util.h", + "$googletest_dir/src/gtest-all.cc", + "$googletest_dir/src/gtest-assertion-result.cc", + "$googletest_dir/src/gtest-death-test.cc", + "$googletest_dir/src/gtest-filepath.cc", + "$googletest_dir/src/gtest-internal-inl.h", + "$googletest_dir/src/gtest-matchers.cc", + "$googletest_dir/src/gtest-port.cc", + "$googletest_dir/src/gtest-printers.cc", + "$googletest_dir/src/gtest-test-part.cc", + "$googletest_dir/src/gtest-typed-test.cc", + "$googletest_dir/src/gtest.cc", + "$googletest_dir/src/hwext/gtest-ext.cc", + "$googletest_dir/src/hwext/gtest-filter.cc", + "$googletest_dir/src/hwext/gtest-multithread.cpp", + "$googletest_dir/src/hwext/gtest-tag.cc", + "$googletest_dir/src/hwext/gtest-utils.cc", +] + static_library("gtest") { testonly = true public = [ "$googletest_dir/include/gtest/gtest-spi.h", "$googletest_dir/include/gtest/gtest.h", ] - sources = [ - "$googletest_dir/include/gtest/gtest-death-test.h", - "$googletest_dir/include/gtest/gtest-matchers.h", - "$googletest_dir/include/gtest/gtest-message.h", - "$googletest_dir/include/gtest/gtest-param-test.h", - "$googletest_dir/include/gtest/gtest-printers.h", - "$googletest_dir/include/gtest/gtest-test-part.h", - "$googletest_dir/include/gtest/gtest-typed-test.h", - "$googletest_dir/include/gtest/gtest_pred_impl.h", - "$googletest_dir/include/gtest/gtest_prod.h", - "$googletest_dir/include/gtest/hwext/gtest-ext.h", - "$googletest_dir/include/gtest/hwext/gtest-filter.h", - "$googletest_dir/include/gtest/hwext/gtest-tag.h", - "$googletest_dir/include/gtest/hwext/utils.h", - "$googletest_dir/include/gtest/internal/custom/gtest-port.h", - "$googletest_dir/include/gtest/internal/custom/gtest-printers.h", - "$googletest_dir/include/gtest/internal/custom/gtest.h", - "$googletest_dir/include/gtest/internal/gtest-death-test-internal.h", - "$googletest_dir/include/gtest/internal/gtest-filepath.h", - "$googletest_dir/include/gtest/internal/gtest-internal.h", - "$googletest_dir/include/gtest/internal/gtest-param-util.h", - "$googletest_dir/include/gtest/internal/gtest-port-arch.h", - "$googletest_dir/include/gtest/internal/gtest-port.h", - "$googletest_dir/include/gtest/internal/gtest-string.h", - "$googletest_dir/include/gtest/internal/gtest-type-util.h", - "$googletest_dir/src/gtest-all.cc", - "$googletest_dir/src/gtest-death-test.cc", - "$googletest_dir/src/gtest-filepath.cc", - "$googletest_dir/src/gtest-internal-inl.h", - "$googletest_dir/src/gtest-matchers.cc", - "$googletest_dir/src/gtest-port.cc", - "$googletest_dir/src/gtest-printers.cc", - "$googletest_dir/src/gtest-test-part.cc", - "$googletest_dir/src/gtest-typed-test.cc", - "$googletest_dir/src/gtest.cc", - "$googletest_dir/src/hwext/gtest-ext.cc", - "$googletest_dir/src/hwext/gtest-filter.cc", - "$googletest_dir/src/hwext/gtest-tag.cc", - "$googletest_dir/src/hwext/gtest-utils.cc", - ] + sources = sources_files sources -= [ "$googletest_dir/src/gtest-all.cc" ] public_configs = [ ":gtest_config" ] configs += [ ":gtest_private_config" ] } +static_library("gtest_rtti") { + testonly = true + public = [ + "$googletest_dir/include/gtest/gtest-spi.h", + "$googletest_dir/include/gtest/gtest.h", + ] + sources = sources_files + sources -= [ "$googletest_dir/src/gtest-all.cc" ] + public_configs = [ ":gtest_config" ] + configs += [ ":gtest_private_config_rtti" ] +} + +static_library("gtest_rtti_main") { # ADD + testonly = true + sources = [ "$googletest_dir/src/gtest_main.cc" ] + public_deps = [ ":gtest_rtti" ] +} + static_library("gtest_main") { testonly = true sources = [ "$googletest_dir/src/gtest_main.cc" ] @@ -91,6 +128,14 @@ config("gmock_private_config") { include_dirs = [ "$googlemock_dir" ] } +config("gmock_private_config_rtti") { + visibility = [ ":*" ] + include_dirs = [ "googlemock_dir/include" ] + cflags = [ "-frtti" ] + cflags_objcc = [ "-frtti" ] + cflags_cc = [ "-frtti" ] +} + config("gmock_config") { include_dirs = [ "$googlemock_dir/include" ] @@ -104,37 +149,49 @@ config("gmock_config") { ] } +gmock_sources_files = [ + "$googlemock_dir/include/gmock/gmock-actions.h", + "$googlemock_dir/include/gmock/gmock-cardinalities.h", + "$googlemock_dir/include/gmock/gmock-function-mocker.h", + "$googlemock_dir/include/gmock/gmock-matchers.h", + "$googlemock_dir/include/gmock/gmock-more-actions.h", + "$googlemock_dir/include/gmock/gmock-more-matchers.h", + "$googlemock_dir/include/gmock/gmock-nice-strict.h", + "$googlemock_dir/include/gmock/gmock-spec-builders.h", + "$googlemock_dir/include/gmock/internal/custom/gmock-generated-actions.h", + "$googlemock_dir/include/gmock/internal/custom/gmock-matchers.h", + "$googlemock_dir/include/gmock/internal/custom/gmock-port.h", + "$googlemock_dir/include/gmock/internal/gmock-internal-utils.h", + "$googlemock_dir/include/gmock/internal/gmock-port.h", + "$googlemock_dir/include/gmock/internal/gmock-pp.h", + "$googlemock_dir/src/gmock-all.cc", + "$googlemock_dir/src/gmock-cardinalities.cc", + "$googlemock_dir/src/gmock-internal-utils.cc", + "$googlemock_dir/src/gmock-matchers.cc", + "$googlemock_dir/src/gmock-spec-builders.cc", + "$googlemock_dir/src/gmock.cc", +] + static_library("gmock") { testonly = true public = [ "$googlemock_dir/include/gmock/gmock.h" ] - sources = [ - "$googlemock_dir/include/gmock/gmock-actions.h", - "$googlemock_dir/include/gmock/gmock-cardinalities.h", - "$googlemock_dir/include/gmock/gmock-function-mocker.h", - "$googlemock_dir/include/gmock/gmock-matchers.h", - "$googlemock_dir/include/gmock/gmock-more-actions.h", - "$googlemock_dir/include/gmock/gmock-more-matchers.h", - "$googlemock_dir/include/gmock/gmock-nice-strict.h", - "$googlemock_dir/include/gmock/gmock-spec-builders.h", - "$googlemock_dir/include/gmock/internal/custom/gmock-generated-actions.h", - "$googlemock_dir/include/gmock/internal/custom/gmock-matchers.h", - "$googlemock_dir/include/gmock/internal/custom/gmock-port.h", - "$googlemock_dir/include/gmock/internal/gmock-internal-utils.h", - "$googlemock_dir/include/gmock/internal/gmock-port.h", - "$googlemock_dir/include/gmock/internal/gmock-pp.h", - "$googlemock_dir/src/gmock-all.cc", - "$googlemock_dir/src/gmock-cardinalities.cc", - "$googlemock_dir/src/gmock-internal-utils.cc", - "$googlemock_dir/src/gmock-matchers.cc", - "$googlemock_dir/src/gmock-spec-builders.cc", - "$googlemock_dir/src/gmock.cc", - ] + sources = gmock_sources_files sources -= [ "$googlemock_dir/src/gmock-all.cc" ] public_configs = [ ":gmock_config" ] configs += [ ":gmock_private_config" ] deps = [ ":gtest" ] } +static_library("gmock_rtti") { + testonly = true + public = [ "$googlemock_dir/include/gmock/gmock.h" ] + sources = gmock_sources_files + sources -= [ "$googlemock_dir/src/gmock-all.cc" ] + public_configs = [ ":gmock_config" ] + configs += [ ":gmock_private_config_rtti" ] + deps = [ ":gtest_rtti" ] +} + static_library("gmock_main") { testonly = true sources = [ "$googlemock_dir/src/gmock_main.cc" ] diff --git a/build/third_party_gn/icu/icu4c/BUILD.gn b/build/third_party_gn/icu/icu4c/BUILD.gn index 082ce8bcb295cd73ae6d28e4207194e612797c72..67d5a36aff5ae0f08a6358f4c6a7e1d678635678 100644 --- a/build/third_party_gn/icu/icu4c/BUILD.gn +++ b/build/third_party_gn/icu/icu4c/BUILD.gn @@ -11,7 +11,12 @@ # See the License for the specific language governing permissions and # limitations under the License. -import("$build_root/ark.gni") +if (ark_standalone_build) { + import("$build_root/ark.gni") +} else { + import("//build/ohos.gni") +} + config("icu_config") { include_dirs = [ "//third_party/icu/icu4c/source/common", @@ -499,13 +504,7 @@ ohos_shared_library("shared_icuuc") { "-shared", "-lm", ] - if (current_os == "ios") { - ldflags += [ - "-Wl", - "-install_name", - "@rpath/libhmicuuc.framework/libhmicuuc", - ] - } + configs = [ ":icu_config", "$build_root/config/compiler:rtti", @@ -552,14 +551,6 @@ ohos_shared_library("shared_icuuc") { install_enable = true } -if (current_os == "ios") { - ohos_combine_darwin_framework("libhmicuuc") { - deps = [ ":shared_icuuc" ] - subsystem_name = "thirdparty" - part_name = "icu" - } -} - ohos_shared_library("shared_icui18n") { ldflags = [ "-shared", diff --git a/build/third_party_gn/libuv/BUILD.gn b/build/third_party_gn/libuv/BUILD.gn index b7276c2629c4ab828d226f694304d929ed7eb283..5bb82bb0329b9ebb64dce4d017162908d2fb0217 100644 --- a/build/third_party_gn/libuv/BUILD.gn +++ b/build/third_party_gn/libuv/BUILD.gn @@ -20,6 +20,7 @@ common_source = [ "//third_party/libuv/src/random.c", "//third_party/libuv/src/strscpy.c", "//third_party/libuv/src/threadpool.c", + "//third_party/libuv/src/thread-common.c", "//third_party/libuv/src/timer.c", "//third_party/libuv/src/uv-common.c", "//third_party/libuv/src/uv-data-getter-setters.c", @@ -28,7 +29,6 @@ common_source = [ ] if (!is_mingw && !is_win) { nonwin_srcs = [ - "//third_party/libuv/src/unix/epoll.c", "//third_party/libuv/src/unix/async.c", "//third_party/libuv/src/unix/core.c", "//third_party/libuv/src/unix/dl.c", @@ -57,6 +57,7 @@ config("libuv_config") { "//third_party/libuv/src", "//third_party/libuv/src/unix", ] + defines = [] cflags = [ "-Wno-unused-parameter" ] if (is_linux || is_ohos) { cflags += [ @@ -68,7 +69,7 @@ config("libuv_config") { # Adding NDEBUG macro manually to avoid compilation # error in debug version, FIX ME # https://gitee.com/openharmony/build/pulls/1206/files - defines = [ "NDEBUG" ] + defines += [ "NDEBUG" ] } else if (is_mingw || is_win) { cflags += [ "-Wno-missing-braces", @@ -79,7 +80,7 @@ config("libuv_config") { "-Wno-error=unknown-pragmas", "-Wno-unused-variable", ] - defines = [ + defines += [ "WIN32_LEAN_AND_MEAN", "_WIN32_WINNT=0x0600", ] @@ -98,7 +99,7 @@ config("libuv_config") { "ws2_32", ] } else if (is_android) { - defines = [ "_GNU_SOURCE" ] + defines += [ "_GNU_SOURCE" ] } } @@ -122,7 +123,7 @@ ohos_source_set("libuv_source") { stack_protector_ret = false configs = [ ":libuv_config" ] sources = common_source - + external_deps = [] if (is_mac || (defined(is_ios) && is_ios)) { sources += nonwin_srcs + [ "//third_party/libuv/src/unix/bsd-ifaddrs.c", @@ -132,8 +133,9 @@ ohos_source_set("libuv_source") { "//third_party/libuv/src/unix/darwin.c", "//third_party/libuv/src/unix/fsevents.c", "//third_party/libuv/src/unix/os390-proctitle.c", + "//third_party/libuv/src/unix/log_unix.c", + "//third_party/libuv/src/unix/trace_unix.c", ] - sources -= [ "//third_party/libuv/src/unix/epoll.c" ] } else if (is_mingw || is_win) { sources += [ "//third_party/libuv/src/win/async.c", @@ -146,6 +148,7 @@ ohos_source_set("libuv_source") { "//third_party/libuv/src/win/getaddrinfo.c", "//third_party/libuv/src/win/getnameinfo.c", "//third_party/libuv/src/win/handle.c", + "//third_party/libuv/src/win/log_win.c", "//third_party/libuv/src/win/loop-watcher.c", "//third_party/libuv/src/win/pipe.c", "//third_party/libuv/src/win/poll.c", @@ -156,6 +159,7 @@ ohos_source_set("libuv_source") { "//third_party/libuv/src/win/stream.c", "//third_party/libuv/src/win/tcp.c", "//third_party/libuv/src/win/thread.c", + "//third_party/libuv/src/win/trace_win.c", "//third_party/libuv/src/win/tty.c", "//third_party/libuv/src/win/udp.c", "//third_party/libuv/src/win/util.c", @@ -164,31 +168,30 @@ ohos_source_set("libuv_source") { ] } else if (is_ohos || (defined(is_android) && is_android)) { sources += nonwin_srcs + [ - "//third_party/libuv/src/unix/linux-core.c", - "//third_party/libuv/src/unix/linux-inotify.c", - "//third_party/libuv/src/unix/linux-syscalls.c", + "//third_party/libuv/src/unix/linux.c", "//third_party/libuv/src/unix/procfs-exepath.c", - "//third_party/libuv/src/unix/pthread-fixes.c", "//third_party/libuv/src/unix/random-getentropy.c", "//third_party/libuv/src/unix/random-getrandom.c", "//third_party/libuv/src/unix/random-sysctl-linux.c", "//third_party/libuv/src/unix/proctitle.c", ] + sources += [ + "src/log_ohos.c", + "src/trace_ohos.c", + ] } else if (is_linux) { sources += nonwin_srcs + [ - "//third_party/libuv/src/unix/linux-core.c", - "//third_party/libuv/src/unix/linux-inotify.c", - "//third_party/libuv/src/unix/linux-syscalls.c", + "//third_party/libuv/src/unix/linux.c", "//third_party/libuv/src/unix/procfs-exepath.c", "//third_party/libuv/src/unix/random-getrandom.c", "//third_party/libuv/src/unix/random-sysctl-linux.c", "//third_party/libuv/src/unix/proctitle.c", + "//third_party/libuv/src/unix/log_unix.c", + "//third_party/libuv/src/unix/trace_unix.c", ] } else { sources += nonwin_srcs + [ - "//third_party/libuv/src/unix/linux-core.c", - "//third_party/libuv/src/unix/linux-inotify.c", - "//third_party/libuv/src/unix/linux-syscalls.c", + "//third_party/libuv/src/unix/linux.c", "//third_party/libuv/src/unix/procfs-exepath.c", "//third_party/libuv/src/unix/random-getrandom.c", "//third_party/libuv/src/unix/random-sysctl-linux.c", diff --git a/build/third_party_gn/libuv/src/log_ohos.c b/build/third_party_gn/libuv/src/log_ohos.c new file mode 100644 index 0000000000000000000000000000000000000000..adca6ab08d69d6cb91a7c406eb3862a12bcccf1f --- /dev/null +++ b/build/third_party_gn/libuv/src/log_ohos.c @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "uv_log.h" + +int uv__log_impl(enum uv__log_level level, const char* fmt, ...) +{ + return 0; +} \ No newline at end of file diff --git a/build/third_party_gn/libuv/src/trace_ohos.c b/build/third_party_gn/libuv/src/trace_ohos.c new file mode 100644 index 0000000000000000000000000000000000000000..d288639d8cb88bf6e3d65609c936eee9366a0e23 --- /dev/null +++ b/build/third_party_gn/libuv/src/trace_ohos.c @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2024 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include +#define UV_TRACE_TAG (1ULL << 30) + +void uv_start_trace(uint64_t tag, const char* name) {} +void uv_end_trace(uint64_t tag) {} \ No newline at end of file diff --git a/build/third_party_gn/musl/BUILD.gn b/build/third_party_gn/musl/BUILD.gn index 2b827ba2e2360f805b25df2aca7c4348eae261f7..73729d5e92377a16ae8e6babd52f13a4ce55a8f4 100644 --- a/build/third_party_gn/musl/BUILD.gn +++ b/build/third_party_gn/musl/BUILD.gn @@ -39,41 +39,46 @@ action("create_porting_src") { outdir = [ "${target_out_dir}/${musl_ported_dir}" ] src_files = musl_src_arch_file - src_files += musl_inc_root_files - src_files += musl_inc_fortify_files - src_files += musl_inc_sys_files - src_files += musl_inc_scsi_files - src_files += musl_inc_netpacket_files - src_files += musl_inc_netinet_files - src_files += musl_inc_net_files - src_files += musl_inc_arpa_files - src_files += musl_inc_bits_files - src_files += musl_src_ldso src_files += musl_src_file + src_files += musl_src_ldso + src_files += musl_inc_bits_files + src_files += musl_inc_arpa_files + src_files += musl_inc_net_files + src_files += musl_inc_netinet_files + src_files += musl_inc_netpacket_files + src_files += musl_inc_scsi_files + src_files += musl_inc_sys_files + src_files += musl_inc_fortify_files + src_files += musl_inc_root_files + src_files += musl_inc_info_files + src_files += musl_inc_trace_files src_files += [ - "scripts/create_syscall.sh", - "scripts/create_vesion.sh", - "scripts/create_alltypes.sh", - "scripts/install.py", - "tools/install.sh", - "tools/version.sh", - "VERSION", - "include/alltypes.h.in", - "arch/${musl_arch}/bits/syscall.h.in", - "arch/${musl_arch}/bits/alltypes.h.in", - "tools/mkalltypes.sed", - "crt/rcrt1.c", - "crt/crt1.c", "crt/Scrt1.c", - "crt/${musl_arch}/crtn.s", + "crt/crt1.c", + "crt/rcrt1.c", + "tools/mkalltypes.sed", + "arch/${musl_arch}/bits/alltypes.h.in", + "arch/${musl_arch}/bits/syscall.h.in", + "include/alltypes.h.in", + "VERSION", + "tools/version.sh", + "tools/install.sh", + "scripts/install.py", + "scripts/create_alltypes.sh", + "scripts/create_vesion.sh", + "scripts/create_syscall.sh", + ] + src_files += [ "crt/${musl_arch}/crti.s", + "crt/${musl_arch}/crtn.s", ] + args = [ "-i" ] + rebase_path(sources_dir) args += [ "-o" ] + rebase_path(outdir) args += [ "-p" ] + [ "${musl_target_os}" ] foreach(i, src_files) { - foreach(s, musl_src_porting_file) { + foreach(s, musl_src_files_ext) { if (i == s) { src_files -= [ "${s}" ] } @@ -85,16 +90,24 @@ action("create_porting_src") { outputs += [ "${target_out_dir}/${musl_ported_dir}/${s}" ] } - foreach(s, musl_src_porting_file) { + foreach(s, musl_src_files_ext) { outputs += [ "${target_out_dir}/${musl_ported_dir}/${s}" ] } + inputs = [] + foreach(i, src_files) { + foreach(s, musl_src_linux_files) { + if (i == s) { + src_files -= [ "${s}" ] + } + } + } foreach(s, src_files) { inputs += [ "${musl_dir}/${s}" ] } - foreach(s, musl_src_porting_file) { - inputs += [ "${musl_porting_dir}/${s}" ] + foreach(s, musl_src_files_ext) { + inputs += [ "${musl_dir}/${s}" ] } } @@ -149,7 +162,7 @@ action("create_syscall_h_file") { } uapi_from = "local" -uapi_full_path = rebase_path(uapi_dir) +uapi_full_path = rebase_path(musl_uapi_dir) arguments_uapi = [ "-c" ] # exclude these files because they need special treatment @@ -166,7 +179,7 @@ uspi_files = exec_script("/bin/sh", arguments_uapi, "list lines") # Generate a copy target for each file foreach(file, uspi_files) { copy("copy_uapi_${file}") { - sources = [ "${uapi_dir}/${file}" ] + sources = [ "${musl_uapi_dir}/${file}" ] outputs = [ "${target_out_dir}/${musl_inc_out_dir}/${file}" ] } } @@ -175,7 +188,7 @@ group("copy_uapi_scsi") { deps = [] sources = [] outputs = [] - uapi_scsi_dir = rebase_path("${uapi_dir}/scsi") + uapi_scsi_dir = rebase_path("${musl_uapi_dir}/scsi") arguments_scsi = [ "-c" ] arguments_scsi += [ "ls ${uapi_scsi_dir}" ] uapi_scsi_files = exec_script("/bin/sh", arguments_scsi, "list lines") @@ -183,7 +196,7 @@ group("copy_uapi_scsi") { # Generate a copy target for each file in scsi dir to avoid being influenced by musl_copy_inc_scsi output foreach(file, uapi_scsi_files) { copy("copy_uapi_scsi_${file}") { - sources += [ "${uapi_dir}/scsi/${file}" ] + sources += [ "${musl_uapi_dir}/scsi/${file}" ] outputs += [ "${target_out_dir}/${musl_inc_out_dir}/scsi/${file}" ] } deps += [ ":copy_uapi_scsi_${file}" ] @@ -197,9 +210,9 @@ copy("copy_uapi_asm") { } else { # aarch64 and x86_64 use same file file_name = "asm-arm64" } - sources = [ "${uapi_dir}/${file_name}/asm" ] + sources = [ "${musl_uapi_dir}/${file_name}/asm" ] } else { - sources = [ "${uapi_dir}/asm" ] + sources = [ "${musl_uapi_dir}/asm" ] } outputs = [ "${target_out_dir}/${musl_inc_out_dir}/asm" ] } diff --git a/build/third_party_gn/musl/musl_config.gni b/build/third_party_gn/musl/musl_config.gni index ceff6198dd837c2423985d0f917889786f025d2b..52814f23281d1df92cb18d28f97a26720d4e9ab8 100644 --- a/build/third_party_gn/musl/musl_config.gni +++ b/build/third_party_gn/musl/musl_config.gni @@ -45,10 +45,10 @@ declare_args() { declare_args() { runtime_lib_path = "//prebuilts/clang/ohos/linux-x86_64/llvm/lib/clang/15.0.4/lib" - use_jemalloc = false + musl_use_jemalloc = false musl_ported_dir = "intermidiates/${musl_target_os}/musl_src_ported" musl_inc_out_dir = "usr/include/${musl_target_triple}" - uapi_dir = "//kernel/linux/patches/linux-5.10/prebuilts/usr/include" + musl_uapi_dir = "//kernel/linux/patches/linux-5.10/prebuilts/usr/include" musl_dir = "//third_party/musl" musl_porting_dir = "//third_party/musl/porting/linux/user" } diff --git a/build/third_party_gn/musl/musl_src.gni b/build/third_party_gn/musl/musl_src.gni index eeb0267d8126784f2978f5c8d485163963591609..aa32f5ccdfeda16c5ba43fd6665ff3d2cbe00860 100644 --- a/build/third_party_gn/musl/musl_src.gni +++ b/build/third_party_gn/musl/musl_src.gni @@ -14,6 +14,7 @@ import("//third_party/FreeBSD/FreeBSD.gni") import("$build_root/third_party_gn/musl/musl_config.gni") +OPTRTDIR = "//third_party/optimized-routines/" if (musl_arch == "arm") { musl_src_arch_file = [ "src/exit/arm/__aeabi_atexit.c", @@ -21,7 +22,6 @@ if (musl_arch == "arm") { "src/fenv/arm/fenv.c", "src/ldso/arm/dlsym.s", "src/ldso/arm/dlsym_time64.S", - "src/ldso/arm/dlvsym.s", "src/ldso/arm/find_exidx.c", "src/ldso/arm/tlsdesc.S", "src/math/arm/fabs.c", @@ -44,6 +44,7 @@ if (musl_arch == "arm") { "src/thread/arm/atomics.s", "src/thread/arm/clone.s", "src/thread/arm/syscall_cp.s", + "src/linux/arm/flock.s", "compat/time32/adjtime32.c", "compat/time32/adjtimex_time32.c", "compat/time32/aio_suspend_time32.c", @@ -113,7 +114,6 @@ if (musl_arch == "arm") { musl_src_arch_file = [ "src/fenv/aarch64/fenv.s", "src/ldso/aarch64/dlsym.s", - "src/ldso/aarch64/dlvsym.s", "src/ldso/aarch64/tlsdesc.s", "src/math/aarch64/ceil.c", "src/math/aarch64/ceilf.c", @@ -152,15 +152,58 @@ if (musl_arch == "arm") { "src/thread/aarch64/__set_thread_area.s", "src/thread/aarch64/__unmapself.s", "src/thread/aarch64/clone.s", - "src/misc/aarch64/fstat.s", "src/thread/aarch64/syscall_cp.s", - "src/misc/aarch64/syscall.s", + "src/linux/aarch64/flock.s", + ] +} else if (musl_arch == "mips") { + musl_src_arch_file = [ + "src/fenv/mips/fenv-sf.c", + "src/fenv/mips/fenv.S", + "src/ldso/mips/dlsym_time64.S", + "src/ldso/mips/dlsym.s", + "src/math/mips/fabs.c", + "src/math/mips/fabsf.c", + "src/math/mips/sqrt.c", + "src/math/mips/sqrtf.c", + "src/setjmp/mips/longjmp.S", + "src/setjmp/mips/setjmp.S", + "src/signal/mips/sigsetjmp.s", + "src/thread/mips/__unmapself.s", + "src/thread/mips/clone.s", + "src/thread/mips/syscall_cp.s", + "src/unistd/mips/pipe.s", + ] +} else if (musl_arch == "riscv64") { + musl_src_arch_file = [ + "src/fenv/riscv64/fenv-sf.c", + "src/fenv/riscv64/fenv.S", + "src/ldso/riscv64/dlsym.s", + "src/ldso/riscv64/tlsdesc.s", + "src/math/riscv64/copysign.c", + "src/math/riscv64/copysignf.c", + "src/math/riscv64/fabs.c", + "src/math/riscv64/fabsf.c", + "src/math/riscv64/fma.c", + "src/math/riscv64/fmaf.c", + "src/math/riscv64/fmax.c", + "src/math/riscv64/fmaxf.c", + "src/math/riscv64/fmin.c", + "src/math/riscv64/fminf.c", + "src/math/riscv64/sqrt.c", + "src/math/riscv64/sqrtf.c", + "src/setjmp/riscv64/longjmp.S", + "src/setjmp/riscv64/setjmp.S", + "src/signal/riscv64/restore.s", + "src/signal/riscv64/sigsetjmp.s", + "src/thread/riscv64/__set_thread_area.s", + "src/thread/riscv64/__unmapself.s", + "src/thread/riscv64/clone.s", + "src/thread/riscv64/syscall_cp.s", ] } else if (musl_arch == "x86_64") { musl_src_arch_file = [ "src/fenv/x86_64/fenv.s", "src/ldso/x86_64/dlsym.s", - "src/ldso/x86_64/dlvsym.s", "src/ldso/x86_64/tlsdesc.s", "src/math/x86_64/__invtrigl.s", "src/math/x86_64/acosl.s", @@ -205,38 +248,32 @@ if (musl_arch == "arm") { "src/thread/x86_64/__unmapself.s", "src/thread/x86_64/clone.s", "src/thread/x86_64/syscall_cp.s", + "src/linux/x86_64/flock.s", ] -} else if (musl_arch == "mips") { +} else if (musl_arch == "loongarch64") { musl_src_arch_file = [ - "src/fenv/mips/fenv.S", - "src/fenv/mips/fenv-sf.c", - "src/ldso/mips/dlsym.s", - "src/ldso/mips/dlsym_time64.S", - "src/math/mips/fabs.c", - "src/math/mips/fabsf.c", - "src/math/mips/sqrt.c", - "src/math/mips/sqrtf.c", - "src/setjmp/mips/longjmp.S", - "src/setjmp/mips/setjmp.S", - "src/signal/mips/restore.s", - "src/signal/mips/sigsetjmp.s", - "src/thread/mips/__unmapself.s", - "src/thread/mips/clone.s", - "src/thread/mips/syscall_cp.s", + "src/fenv/loongarch64/fenv.S", + "src/ldso/loongarch64/dlsym.s", + "src/ldso/loongarch64/tlsdesc.s", + "src/setjmp/loongarch64/longjmp.S", + "src/setjmp/loongarch64/setjmp.S", + "src/signal/loongarch64/restore.s", + "src/signal/loongarch64/sigsetjmp.s", + "src/thread/loongarch64/__set_thread_area.s", + "src/thread/loongarch64/__unmapself.s", + "src/thread/loongarch64/clone.s", + "src/thread/loongarch64/syscall_cp.s", ] } musl_src_file = [ - "src/thread/pthread_cond_clockwait.c", - "src/thread/pthread_cond_timedwait_monotonic_np.c", - "src/thread/pthread_cond_timeout_np.c", "src/internal/pthread_impl.h", "src/internal/locale_impl.h", - "src/thread/pthread_rwlock_clockrdlock.c", + "src/internal/locale_impl.c", + "src/internal/stdio_impl.h", + "src/internal/unsupported_api.h", + "src/internal/syscall_hooks.h", "src/thread/pthread_rwlock_timedrdlock.c", - "src/thread/pthread_rwlock_timedrdlock_monotonic_np.c", - "src/thread/pthread_rwlock_clockwrlock.c", - "src/thread/pthread_rwlock_timedwrlock_monotonic_np.c", "src/thread/pthread_rwlock_timedwrlock.c", "src/aio/aio.c", "src/aio/aio_suspend.c", @@ -391,6 +428,7 @@ musl_src_file = [ "src/exit/at_quick_exit.c", "src/exit/atexit.c", "src/exit/exit.c", + "src/exit/cxa_thread_atexit_impl.c", "src/exit/quick_exit.c", "src/fcntl/creat.c", "src/fcntl/fcntl.c", @@ -398,6 +436,7 @@ musl_src_file = [ "src/fcntl/openat.c", "src/fcntl/posix_fadvise.c", "src/fcntl/posix_fallocate.c", + "src/fdsan/fdsan.c", "src/fenv/__flt_rounds.c", "src/fenv/fegetexceptflag.c", "src/fenv/feholdexcept.c", @@ -406,6 +445,8 @@ musl_src_file = [ "src/fenv/fesetround.c", "src/fenv/feupdateenv.c", "src/fortify/fortify.c", + "src/gwp_asan/gwp_asan.c", + "src/gwp_asan/gwp_asan.h", "src/internal/defsysinfo.c", "src/internal/floatscan.c", "src/internal/intscan.c", @@ -413,9 +454,7 @@ musl_src_file = [ "src/internal/procfdname.c", "src/internal/shgetc.c", "src/internal/syscall_ret.c", - "src/internal/vdso.c", "src/internal/version.c", - "src/internal/network_conf_function.c", "src/hilog/hilog_adapter.c", "src/hilog/vsnprintf_s_p.c", "src/ipc/ftok.c", @@ -488,15 +527,14 @@ musl_src_file = [ "src/linux/open_by_handle_at.c", "src/linux/personality.c", "src/linux/pivot_root.c", - "src/linux/ppoll.c", "src/linux/prctl.c", + "src/linux/preadv2.c", "src/linux/prlimit.c", "src/linux/process_vm.c", "src/linux/ptrace.c", "src/linux/quotactl.c", "src/linux/readahead.c", "src/linux/reboot.c", - "src/linux/tgkill.c", "src/linux/remap_file_pages.c", "src/linux/sbrk.c", "src/linux/sendfile.c", @@ -508,6 +546,7 @@ musl_src_file = [ "src/linux/settimeofday.c", "src/linux/signalfd.c", "src/linux/splice.c", + "src/linux/statx.c", "src/linux/stime.c", "src/linux/swap.c", "src/linux/sync_file_range.c", @@ -521,6 +560,7 @@ musl_src_file = [ "src/linux/vmsplice.c", "src/linux/wait3.c", "src/linux/wait4.c", + "src/linux/pwritev2.c", "src/linux/xattr.c", "src/locale/__lctrans.c", "src/locale/__mo_lookup.c", @@ -542,6 +582,7 @@ musl_src_file = [ "src/locale/setlocale.c", "src/locale/strcoll.c", "src/locale/strtod_l.c", + "src/locale/wcstod_l.c", "src/locale/strfmon.c", "src/locale/strxfrm.c", "src/locale/textdomain.c", @@ -556,8 +597,6 @@ musl_src_file = [ "src/malloc/mallocng/malloc.c", "src/malloc/mallocng/meta.h", "src/malloc/mallocng/realloc.c", - "src/malloc/stats.c", - "src/malloc/calloc.c", "src/malloc/free.c", "src/malloc/libc_calloc.c", "src/malloc/lite_malloc.c", @@ -1029,6 +1068,7 @@ musl_src_file = [ "src/regex/regerror.c", "src/regex/regexec.c", "src/regex/tre-mem.c", + "src/syscall_hooks/syscall_hooks.c", "src/sched/sched_cpualloc.c", "src/sched/affinity.c", "src/sched/sched_cpucount.c", @@ -1049,6 +1089,7 @@ musl_src_file = [ "src/search/tsearch.c", "src/search/twalk.c", "src/select/poll.c", + "src/select/ppoll.c", "src/select/pselect.c", "src/select/select.c", "src/setjmp/longjmp.c", @@ -1091,7 +1132,6 @@ musl_src_file = [ "src/signal/sigtimedwait.c", "src/signal/sigwait.c", "src/signal/sigwaitinfo.c", - "src/sigchain/sigchain.c", "src/stat/__xstat.c", "src/stat/chmod.c", "src/stat/fchmod.c", @@ -1250,6 +1290,7 @@ musl_src_file = [ "src/stdlib/strtol.c", "src/stdlib/wcstod.c", "src/stdlib/wcstol.c", + "src/string/strcspn.c", "src/string/bcmp.c", "src/string/bcopy.c", "src/string/bzero.c", @@ -1268,13 +1309,11 @@ musl_src_file = [ "src/string/stpcpy.c", "src/string/stpncpy.c", "src/string/strcasecmp.c", - "src/string/strcasestr.c", "src/string/strcat.c", "src/string/strchr.c", "src/string/strchrnul.c", "src/string/strcmp.c", "src/string/strcpy.c", - "src/string/strcspn.c", "src/string/strdup.c", "src/string/strerror_r.c", "src/string/strlcat.c", @@ -1415,9 +1454,6 @@ musl_src_file = [ "src/thread/pthread_mutex_lock.c", "src/thread/pthread_mutex_setprioceiling.c", "src/thread/pthread_mutex_timedlock.c", - "src/thread/pthread_mutex_clocklock.c", - "src/thread/pthread_mutex_timedlock_monotonic_np.c", - "src/thread/pthread_mutex_lock_timeout_np.c", "src/thread/pthread_mutex_trylock.c", "src/thread/pthread_mutex_unlock.c", "src/thread/pthread_mutexattr_destroy.c", @@ -1596,6 +1632,39 @@ musl_src_file = [ "src/info/application_target_sdk_version.c", "src/info/device_api_version.c", "src/info/fatal_message.c", + "arch/generic/crtbrand.s", + "crt/crtplus.c", + "ldso/namespace.h", + "ldso/ns_config.h", + "ldso/strops.h", + "ldso/cfi.h", + "ldso/ld_log.h", + "ldso/dynlink_rand.h", + "src/internal/vdso.c", + "src/internal/emulate_wait4.c", + "src/internal/malloc_config.h", + "src/internal/malloc_random.h", + "src/internal/hilog_adapter.h", + "src/internal/musl_log.h", + "src/internal/musl_log.c", + "src/internal/network_conf_function.c", + "src/internal/network_conf_function.h", + "src/internal/services.h", + "src/internal/proc_xid_impl.h", + "src/linux/tgkill.c", + "src/malloc/calloc.c", + "src/malloc/stats.c", + "src/sigchain/sigchain.c", + "src/thread/pthread_cond_clockwait.c", + "src/thread/pthread_cond_timedwait_monotonic_np.c", + "src/thread/pthread_cond_timeout_np.c", + "src/thread/pthread_mutex_clocklock.c", + "src/thread/pthread_mutex_timedlock_monotonic_np.c", + "src/thread/pthread_mutex_lock_timeout_np.c", + "src/thread/pthread_rwlock_clockrdlock.c", + "src/thread/pthread_rwlock_timedrdlock_monotonic_np.c", + "src/thread/pthread_rwlock_clockwrlock.c", + "src/thread/pthread_rwlock_timedwrlock_monotonic_np.c", ] if (musl_arch == "arm") { @@ -1718,13 +1787,54 @@ if (musl_arch == "arm") { musl_src_filterout = [ "src/fenv/fenv.c", "src/ldso/dlsym.c", + "src/ldso/tlsdesc.c", + "src/math/fabs.c", + "src/math/fabsf.c", + "src/math/sqrt.c", + "src/math/sqrtf.c", + "src/setjmp/longjmp.c", + "src/setjmp/setjmp.c", + "src/signal/restore.c", + "src/signal/sigsetjmp.c", + "src/thread/__unmapself.c", + "src/thread/clone.c", + "src/thread/syscall_cp.c", + "src/unistd/pipe.c", + ] +} else if (musl_arch == "riscv64") { + musl_src_filterout = [ + "src/fenv/fenv.c", + "src/ldso/dlsym.c", + "src/ldso/tlsdesc.c", "src/math/fabs.c", "src/math/fabsf.c", + "src/math/fma.c", "src/math/fmaf.c", + "src/math/fmax.c", + "src/math/fmaxf.c", + "src/math/fmin.c", + "src/math/fminf.c", "src/math/sqrt.c", "src/math/sqrtf.c", + "src/setjmp/longjmp.c", "src/setjmp/setjmp.c", "src/signal/restore.c", + "src/signal/sigsetjmp.c", + "src/thread/__set_thread_area.c", + "src/thread/__unmapself.c", + "src/thread/clone.c", + "src/thread/syscall_cp.c", + ] +} else if (musl_arch == "loongarch64") { + musl_src_filterout = [ + "src/fenv/fenv.c", + "src/ldso/dlsym.c", + "src/ldso/tlsdesc.c", + "src/setjmp/longjmp.c", + "src/setjmp/setjmp.c", + "src/signal/restore.c", + "src/signal/sigsetjmp.c", + "src/thread/__set_thread_area.c", "src/thread/__unmapself.c", "src/thread/clone.c", "src/thread/syscall_cp.c", @@ -1828,7 +1938,6 @@ if (musl_arch == "arm") { "arch/x86_64/bits/stat.h", "arch/x86_64/bits/stdint.h", "arch/x86_64/bits/user.h", - "arch/generic/bits/dirent.h", "arch/generic/bits/errno.h", "arch/generic/bits/hwcap.h", @@ -1855,40 +1964,115 @@ if (musl_arch == "arm") { ] } else if (musl_arch == "mips") { musl_inc_bits_files = [ - "arch/mips/bits/errno.h", - "arch/mips/bits/fcntl.h", + "arch/generic/bits/fcntl.h", "arch/mips/bits/fenv.h", "arch/mips/bits/float.h", - "arch/mips/bits/hwcap.h", - "arch/mips/bits/ioctl.h", - "arch/mips/bits/ipcstat.h", - "arch/mips/bits/mman.h", - "arch/mips/bits/msg.h", - "arch/mips/bits/poll.h", "arch/mips/bits/posix.h", - "arch/mips/bits/ptrace.h", "arch/mips/bits/reg.h", - "arch/mips/bits/resource.h", - "arch/mips/bits/sem.h", "arch/mips/bits/setjmp.h", - "arch/mips/bits/shm.h", "arch/mips/bits/signal.h", - "arch/mips/bits/socket.h", "arch/mips/bits/stat.h", - "arch/mips/bits/statfs.h", "arch/mips/bits/stdint.h", - "arch/mips/bits/termios.h", "arch/mips/bits/user.h", + "arch/generic/bits/dirent.h", + "arch/generic/bits/errno.h", + "arch/generic/bits/hwcap.h", "arch/generic/bits/ioctl_fix.h", + "arch/generic/bits/ioctl.h", "arch/generic/bits/io.h", "arch/generic/bits/ipc.h", + "arch/generic/bits/ipcstat.h", "arch/generic/bits/kd.h", "arch/generic/bits/limits.h", "arch/generic/bits/link.h", + "arch/generic/bits/mman.h", + "arch/generic/bits/msg.h", + "arch/generic/bits/poll.h", + "arch/generic/bits/ptrace.h", + "arch/generic/bits/resource.h", + "arch/generic/bits/sem.h", + "arch/generic/bits/shm.h", + "arch/generic/bits/socket.h", "arch/generic/bits/soundcard.h", + "arch/generic/bits/statfs.h", + "arch/generic/bits/termios.h", "arch/generic/bits/vt.h", ] +} else if (musl_arch == "riscv64") { + musl_inc_bits_files = [ + "arch/generic/bits/fcntl.h", + "arch/riscv64/bits/fenv.h", + "arch/riscv64/bits/float.h", + "arch/riscv64/bits/posix.h", + "arch/riscv64/bits/reg.h", + "arch/riscv64/bits/setjmp.h", + "arch/riscv64/bits/signal.h", + "arch/riscv64/bits/stat.h", + "arch/riscv64/bits/stdint.h", + "arch/riscv64/bits/user.h", + + "arch/generic/bits/dirent.h", + "arch/generic/bits/errno.h", + "arch/generic/bits/hwcap.h", + "arch/generic/bits/ioctl_fix.h", + "arch/generic/bits/ioctl.h", + "arch/generic/bits/io.h", + "arch/generic/bits/ipc.h", + "arch/generic/bits/ipcstat.h", + "arch/generic/bits/kd.h", + "arch/generic/bits/limits.h", + "arch/generic/bits/link.h", + "arch/generic/bits/mman.h", + "arch/generic/bits/msg.h", + "arch/generic/bits/poll.h", + "arch/generic/bits/ptrace.h", + "arch/generic/bits/resource.h", + "arch/generic/bits/sem.h", + "arch/generic/bits/shm.h", + "arch/generic/bits/socket.h", + "arch/generic/bits/soundcard.h", + "arch/generic/bits/statfs.h", + "arch/generic/bits/termios.h", + "arch/generic/bits/vt.h", + ] +} else if (musl_arch == "loongarch64") { + musl_inc_bits_files = [ + "arch/loongarch64/bits/fenv.h", + "arch/loongarch64/bits/float.h", + "arch/loongarch64/bits/posix.h", + "arch/loongarch64/bits/reg.h", + "arch/loongarch64/bits/setjmp.h", + "arch/loongarch64/bits/signal.h", + "arch/loongarch64/bits/stat.h", + "arch/loongarch64/bits/stdint.h", + "arch/loongarch64/bits/user.h", + + "arch/generic/bits/dirent.h", + "arch/generic/bits/errno.h", + "arch/generic/bits/hwcap.h", + "arch/generic/bits/ioctl_fix.h", + "arch/generic/bits/ioctl.h", + "arch/generic/bits/io.h", + "arch/generic/bits/ipc.h", + "arch/generic/bits/ipcstat.h", + "arch/generic/bits/kd.h", + "arch/generic/bits/link.h", + "arch/generic/bits/mman.h", + "arch/generic/bits/msg.h", + "arch/generic/bits/poll.h", + "arch/generic/bits/sem.h", + "arch/generic/bits/shm.h", + "arch/generic/bits/socket.h", + "arch/generic/bits/soundcard.h", + "arch/generic/bits/termios.h", + "arch/generic/bits/vt.h", + "arch/generic/bits/statfs.h", + "arch/generic/bits/ptrace.h", + "arch/generic/bits/resource.h", + "arch/generic/bits/fcntl.h", + "arch/generic/bits/limits.h", + ] } musl_inc_arpa_files = [ @@ -2117,239 +2301,245 @@ musl_inc_root_files = [ "include/wchar.h", "include/wctype.h", "include/wordexp.h", + "include/syscall_hooks.h", + "include/pthread_ffrt.h", ] -musl_src_porting_file = [ - "arch/aarch64/syscall_arch.h", - "arch/arm/bits/fenv.h", - "arch/generic/bits/shm.h", - "arch/generic/crtbrand.s", - "arch/x86_64/bits/float.h", - "include/ctype.h", - "include/info/application_target_sdk_version.h", - "include/info/device_api_version.h", - "include/info/fatal_message.h", - "include/malloc.h", - "include/pthread.h", - "include/fcntl.h", - "include/poll.h", - "include/stdio.h", - "include/stdlib.h", - "include/string.h", - "include/sys/stat.h", - "include/sys/sspret.h", - "include/sys/cdefs.h", - "include/fortify/fcntl.h", - "include/fortify/fortify.h", - "include/fortify/poll.h", - "include/fortify/socket.h", - "include/fortify/stat.h", - "include/fortify/stdlib.h", - "include/fortify/string.h", - "include/fortify/unistd.h", - "include/fortify/stdio.h", +musl_src_files_ext = [ + "src/internal/linux/musl_log.c", + "src/internal/linux/vdso.c", + "src/hook/linux/malloc_common.c", + "src/hook/linux/musl_preinit.c", + "src/hook/linux/musl_socket_preinit.c", + "src/hook/linux/socket_common.c", + "src/hook/linux/memory_trace.c", + "src/hook/linux/musl_fdtrack.c", + "src/hook/linux/musl_fdtrack_load.c", + "src/hook/linux/musl_preinit_common.c", + "src/hook/linux/musl_socket_preinit_common.c", + "crt/linux/crtplus.c", + "src/linux/arm/linux/flock.s", + "src/linux/aarch64/linux/flock.s", + "src/linux/x86_64/linux/flock.s", + "src/exit/linux/assert.c", + "src/exit/linux/atexit.c", + "src/fdsan/linux/fdsan.c", + "src/fortify/linux/fortify.c", + "src/gwp_asan/linux/gwp_asan.c", + "src/gwp_asan/linux/gwp_asan.h", + "src/hilog/linux/hilog_adapter.c", + "src/hilog/linux/hilog_common.h", + "src/hilog/linux/output_p.inl", + "src/hilog/linux/vsnprintf_s_p.c", + "src/hilog/linux/vsnprintf_s_p.h", + "src/linux/linux/clone.c", + "src/linux/linux/getprocpid.c", + "src/network/linux/getaddrinfo.c", + "src/syscall_hooks/linux/syscall_hooks.c", + "src/signal/linux/sigaction.c", + "src/thread/linux/pthread_create.c", + "src/trace/linux/trace_marker.c", + "include/trace/linux/trace_marker.h", + "src/info/linux/application_target_sdk_version.c", + "src/info/linux/device_api_version.c", + "src/info/linux/fatal_message.c", + "ldso/linux/cfi.c", + "ldso/linux/dynlink.c", + "ldso/linux/dynlink_rand.h", + "ldso/linux/ld_log.h", + "ldso/linux/namespace.h", + "ldso/linux/ns_config.h", + "ldso/linux/strops.c", + "ldso/linux/zip_archive.h", + "ldso/linux/cfi.h", + "ldso/linux/dynlink_rand.c", + "ldso/linux/ld_log.c", + "ldso/linux/namespace.c", + "ldso/linux/ns_config.c", + "ldso/linux/strops.h", + "include/sys/linux/capability.h", + "include/sys/linux/cdefs.h", + "include/sys/linux/sspret.h", + "include/info/linux/application_target_sdk_version.h", + "include/info/linux/device_api_version.h", + "include/info/linux/fatal_message.h", + "include/fortify/linux/fcntl.h", + "include/fortify/linux/poll.h", + "include/fortify/linux/stat.h", + "include/fortify/linux/stdlib.h", + "include/fortify/linux/unistd.h", + "include/fortify/linux/fortify.h", + "include/fortify/linux/socket.h", + "include/fortify/linux/stdio.h", + "include/fortify/linux/string.h", + "include/linux/dlfcn_ext.h", + "include/linux/sigchain.h", + "include/linux/syscall_hooks.h", + "src/ldso/arm/linux/dlvsym.s", + "src/ldso/aarch64/linux/dlvsym.s", + "src/ldso/x86_64/linux/dlvsym.s", + "src/misc/aarch64/linux/fstat.s", + "src/misc/aarch64/linux/syscall.s", + "src/malloc/linux/calloc.c", + "src/malloc/linux/stats.c", + "src/sigchain/linux/sigchain.c", + "src/internal/linux/malloc_config.h", + "src/internal/linux/proc_xid_impl.h", + "src/internal/linux/malloc_random.h", + "src/internal/linux/musl_log.h", + "src/internal/linux/syscall_hooks.h", + "src/hook/linux/common_def.h", + "src/hook/linux/musl_fdtrack.h", + "src/hook/linux/musl_fdtrack_hook.h", + "src/hook/linux/musl_malloc_dispatch.h", + "src/hook/linux/musl_malloc_dispatch_table.h", + "src/hook/linux/musl_preinit_common.h", + "src/hook/linux/musl_malloc.h", + "src/hook/linux/musl_socket_dispatch.h", + "src/hook/linux/musl_socket_preinit_common.h", + "src/hook/linux/memory_trace.h", + "src/hook/linux/musl_socket.h", +] + +musl_src_linux_files = [ + "src/internal/malloc_config.h", + "src/internal/proc_xid_impl.h", + "src/internal/malloc_random.h", + "src/internal/musl_log.h", + "src/internal/syscall_hooks.h", + "src/hook/common_def.h", + "src/hook/musl_fdtrack.h", + "src/hook/musl_fdtrack_hook.h", + "src/hook/musl_malloc_dispatch.h", + "src/hook/musl_malloc_dispatch_table.h", + "src/hook/musl_preinit_common.h", + "src/hook/musl_malloc.h", + "src/hook/musl_socket_dispatch.h", + "src/hook/musl_socket_preinit_common.h", + "src/hook/memory_trace.h", + "src/hook/musl_socket.h", + "src/internal/musl_log.c", + "src/internal/vdso.c", + "src/hook/malloc_common.c", + "src/hook/musl_preinit.c", + "src/hook/musl_socket_preinit.c", + "src/hook/socket_common.c", + "src/hook/memory_trace.c", + "src/hook/musl_fdtrack.c", + "src/hook/musl_fdtrack_load.c", + "src/hook/musl_preinit_common.c", + "src/hook/musl_socket_preinit_common.c", + "crt/crtplus.c", + "src/linux/arm/flock.s", + "src/linux/aarch64/flock.s", + "src/linux/x86_64/flock.s", + "src/exit/assert.c", + "src/exit/atexit.c", + "src/fdsan/fdsan.c", "src/fortify/fortify.c", - "include/sys/capability.h", - "include/sys/reboot.h", - "include/sys/socket.h", - "include/sys/sysinfo.h", - "include/signal.h", - "include/sigchain.h", - "include/sched.h", - "src/internal/dynlink.h", - "include/sys/tgkill.h", - "include/trace/trace_marker.h", - "include/unistd.h", - "include/dlfcn.h", - "include/dlfcn_ext.h", - "src/fcntl/open.c", + "src/gwp_asan/gwp_asan.c", + "src/gwp_asan/gwp_asan.h", + "src/hilog/hilog_adapter.c", "src/hilog/hilog_common.h", + "src/hilog/output_p.inl", + "src/hilog/vsnprintf_s_p.c", "src/hilog/vsnprintf_s_p.h", - "src/internal/hilog_adapter.h", - "src/internal/musl_log.h", - "src/info/application_target_sdk_version.c", - "src/info/device_api_version.c", - "src/info/fatal_message.c", - "src/env/__init_tls.c", - "src/env/__libc_start_main.c", - "src/internal/pthread_impl.h", - "src/internal/locale_impl.h", - "src/internal/syscall.h", - "src/internal/services.h", - "src/internal/network_conf_function.h", - "src/internal/network_conf_function.c", - "src/internal/proc_xid_impl.h", - "ldso/namespace.h", - "ldso/ns_config.h", - "ldso/strops.h", - "src/legacy/ulimit.c", "src/linux/clone.c", "src/linux/getprocpid.c", - "src/linux/reboot.c", - "src/linux/tgkill.c", - "src/malloc/mallocng/malloc_usable_size.c", - "src/malloc/mallocng/malloc.c", - "src/malloc/mallocng/meta.h", - "src/malloc/mallocng/donate.c", - "src/malloc/mallocng/aligned_alloc.c", - "src/malloc/lite_malloc.c", - "src/malloc/stats.c", - "src/malloc/calloc.c", - "src/malloc/free.c", - "src/network/getnameinfo.c", - "src/malloc/libc_calloc.c", - "src/malloc/realloc.c", - "src/network/inet_legacy.c", - "src/network/lookup_name.c", - "src/network/lookup_serv.c", - "src/network/resolvconf.c", - "src/network/socket.c", - "src/passwd/getspnam_r.c", - "src/sched/sched_setparam.c", - "src/sched/sched_getparam.c", - "src/sched/sched_setscheduler.c", - "src/sched/sched_getscheduler.c", - "src/thread/arm/clone.s", - "src/thread/arm/syscall_cp.s", - "src/thread/pthread_mutex_clocklock.c", - "src/thread/pthread_mutex_timedlock.c", - "src/thread/pthread_mutex_lock.c", - "src/thread/pthread_mutex_timedlock_monotonic_np.c", - "src/thread/pthread_mutex_lock_timeout_np.c", - "src/thread/pthread_mutex_init.c", - "src/thread/pthread_rwlock_clockrdlock.c", - "src/thread/pthread_rwlock_timedrdlock.c", - "src/thread/pthread_rwlock_timedrdlock_monotonic_np.c", - "src/thread/pthread_rwlock_init.c", - "src/thread/pthread_cond_timedwait.c", - "src/thread/pthread_cond_timedwait_monotonic_np.c", - "src/thread/pthread_cond_timeout_np.c", - "src/thread/pthread_cond_clockwait.c", - "src/thread/pthread_cond_init.c", + "src/network/getaddrinfo.c", + "src/syscall_hooks/syscall_hooks.c", + "src/signal/sigaction.c", "src/thread/pthread_create.c", - "src/thread/pthread_rwlock_clockwrlock.c", - "src/thread/pthread_rwlock_timedwrlock_monotonic_np.c", - "src/thread/pthread_rwlock_timedwrlock.c", - "src/thread/pthread_sigmask.c", "src/trace/trace_marker.c", - "src/ldso/dlclose.c", - "src/ldso/dlerror.c", + "include/trace/trace_marker.h", + "src/info/application_target_sdk_version.c", + "src/info/device_api_version.c", + "src/info/fatal_message.c", + "ldso/cfi.c", "ldso/dynlink.c", - "src/exit/atexit.c", - "crt/arm/crti.s", - "crt/aarch64/crti.s", - "crt/crtplus.c", - "ldso/cfi.h", + "ldso/dynlink_rand.h", "ldso/ld_log.h", + "ldso/namespace.h", + "ldso/ns_config.h", + "ldso/strops.c", + "ldso/zip_archive.h", + "ldso/cfi.h", + "ldso/dynlink_rand.c", "ldso/ld_log.c", "ldso/namespace.c", "ldso/ns_config.c", - "ldso/strops.c", - "ldso/cfi.c", - "ldso/dynlink_rand.c", - "ldso/dynlink_rand.h", - "src/sched/sched_cpualloc.c", - "src/signal/signal.c", - "src/signal/sigaction.c", - "src/signal/siginterrupt.c", - "include/langinfo.h", - "include/locale.h", - "src/hilog/hilog_adapter.c", - "src/hilog/vsnprintf_s_p.c", - "src/internal/libc.h", - "src/locale/dcngettext.c", - "src/locale/locale_map.c", - "src/locale/langinfo.c", - "src/locale/newlocale.c", - "src/time/__tz.c", - "src/time/gmtime_r.c", - "src/time/strftime.c", - "src/time/strptime.c", - "src/time/time_impl.h", - "src/ldso/aarch64/dlvsym.s", + "ldso/strops.h", + "include/sys/capability.h", + "include/sys/cdefs.h", + "include/sys/sspret.h", + "include/info/application_target_sdk_version.h", + "include/info/device_api_version.h", + "include/info/fatal_message.h", + "include/fortify/fcntl.h", + "include/fortify/poll.h", + "include/fortify/stat.h", + "include/fortify/stdlib.h", + "include/fortify/unistd.h", + "include/fortify/fortify.h", + "include/fortify/socket.h", + "include/fortify/stdio.h", + "include/fortify/string.h", + "include/dlfcn_ext.h", + "include/sigchain.h", + "include/syscall_hooks.h", "src/ldso/arm/dlvsym.s", - "src/ldso/riscv64/dlvsym.s", + "src/ldso/aarch64/dlvsym.s", "src/ldso/x86_64/dlvsym.s", - "src/stdio/__fdopen.c", - "src/stdio/vfprintf.c", - "src/stdio/__stdio_read.c", - "src/stdio/__stdio_write.c", - "src/stdio/__stdout_write.c", - "src/stdio/fread.c", - "src/stdio/fmemopen.c", - "src/stdio/freopen.c", - "src/stdio/stdin.c", - "src/stdio/__fmodeflags.c", - "src/stdio/fopen.c", - "src/stdio/ofl.c", - "src/stdio/fclose.c", - "src/stdio/__toread.c", - "src/stdio/__towrite.c", - "src/stdio/stderr.c", - "src/stdio/fgets.c", - "src/stdio/vsnprintf.c", - "src/stdio/vsscanf.c", - "src/internal/stdio_impl.h", - "src/internal/vdso.c", - "src/time/clock_gettime.c", - "src/time/clock_getres.c", - "src/time/gettimeofday.c", - "src/time/time.c", - "src/unistd/getpid.c", - "src/process/_Fork.c", - "src/process/vfork.c", - "src/process/arm/__vfork.s", - "src/process/x86_64/__vfork.s", - "src/linux/cache.c", - "src/sched/sched_getcpu.c", - "src/sigchain/sigchain.c", - "src/conf/legacy.c", - "src/conf/sysconf.c", - "src/env/getenv.c", - "src/string/strcasecmp.c", - "src/string/strncasecmp.c", - "src/string/strncat.c", - "src/string/stpncpy.c", - "src/string/strncpy.c", - "src/stat/fstat.c", - "src/string/strcspn.c", - "src/thread/pthread_once.c", - "src/thread/pthread_cancel.c", - "src/mq/mq_notify.c", - "src/aio/aio.c", "src/misc/aarch64/fstat.s", "src/misc/aarch64/syscall.s", - "src/stdlib/strtol.c", - "src/stdlib/strtod.c", - "src/thread/sem_timedwait.c", - "src/stdio/vfscanf.c", - "src/stdio/fileno.c", + "src/malloc/calloc.c", + "src/malloc/stats.c", + "src/sigchain/sigchain.c", ] +if (musl_arch == "arm") { + musl_src_file += [ + "src/process/arm/__vfork.s", + "src/ldso/arm/dlvsym.s", + ] +} else if (musl_arch == "aarch64") { + musl_src_file += [ + "arch/aarch64/syscall_arch.h", + "src/misc/aarch64/fstat.s", + "src/misc/aarch64/syscall.s", + "src/ldso/aarch64/dlvsym.s", + ] +} else if (musl_arch == "loongarch64") { + musl_src_file += [ "arch/loongarch64/syscall_arch.h" ] +} else if (musl_arch == "x86_64") { + musl_src_file += [ + "src/process/x86_64/__vfork.s", + "src/ldso/x86_64/dlvsym.s", + ] +} + musl_inc_hook_files = [ - "//third_party/musl/porting/linux/user/src/internal/hilog_adapter.h", - "//third_party/musl/porting/linux/user/src/internal/musl_log.h", - "//third_party/musl/porting/linux/user/src/hook/memory_trace.h", - "//third_party/musl/porting/linux/user/src/hook/musl_malloc_dispatch_table.h", - "//third_party/musl/porting/linux/user/src/hook/musl_malloc_dispatch.h", - "//third_party/musl/porting/linux/user/src/hook/musl_preinit_common.h", + "//third_party/musl/src/internal/hilog_adapter.h", + "//third_party/musl/src/internal/linux/musl_log.h", + "//third_party/musl/src/hook/linux/memory_trace.h", + "//third_party/musl/src/hook/linux/musl_fdtrack.h", + "//third_party/musl/src/hook/linux/musl_fdtrack_hook.h", + "//third_party/musl/src/hook/linux/musl_malloc_dispatch_table.h", + "//third_party/musl/src/hook/linux/musl_malloc_dispatch.h", + "//third_party/musl/src/hook/linux/musl_preinit_common.h", + "//third_party/musl/src/hook/linux/musl_socket_dispatch.h", ] added_freebsd_files = [ - "$FREEBSD_DIR/contrib/gdtoa/strtod.c", - "$FREEBSD_DIR/contrib/gdtoa/gethex.c", - "$FREEBSD_DIR/contrib/gdtoa/smisc.c", - "$FREEBSD_DIR/contrib/gdtoa/misc.c", - "$FREEBSD_DIR/contrib/gdtoa/strtord.c", - "$FREEBSD_DIR/contrib/gdtoa/hexnan.c", - "$FREEBSD_DIR/contrib/gdtoa/gmisc.c", - "$FREEBSD_DIR/contrib/gdtoa/hd_init.c", - "$FREEBSD_DIR/contrib/gdtoa/strtodg.c", - "$FREEBSD_DIR/contrib/gdtoa/ulp.c", - "$FREEBSD_DIR/contrib/gdtoa/strtof.c", - "$FREEBSD_DIR/contrib/gdtoa/sum.c", - "$FREEBSD_DIR/lib/libc/gdtoa/glue.c", - "$FREEBSD_DIR/lib/libc/stdio/parsefloat.c", + "$FREEBSD_DIR/contrib/tcp_wrappers/strcasecmp.c", + "$FREEBSD_DIR/lib/libc/gen/arc4random.c", + "$FREEBSD_DIR/lib/libc/gen/arc4random_uniform.c", + "$FREEBSD_DIR/lib/libc/stdlib/qsort.c", + "$FREEBSD_DIR/lib/libc/stdlib/strtoimax.c", + "$FREEBSD_DIR/lib/libc/stdlib/strtoul.c", + "$FREEBSD_DIR/lib/libc/stdlib/strtoumax.c", ] +freebsd_headers = [ "$FREEBSD_DIR/contrib/libexecinfo/execinfo.h" ] + freebsd_sys_headers = [ "$FREEBSD_DIR/sys/sys/queue.h" ] diff --git a/build/third_party_gn/musl/musl_template.gni b/build/third_party_gn/musl/musl_template.gni index 84c653b5fdc1d8e9ac79ac18fa81a2c673da2031..c62f882fa666d5916e7a52046c09ac0d5266cd17 100644 --- a/build/third_party_gn/musl/musl_template.gni +++ b/build/third_party_gn/musl/musl_template.gni @@ -302,6 +302,7 @@ template("musl_libs") { "//third_party/jemalloc/include/", "//third_party/jemalloc/include/jemalloc/internal", "//third_party/jemalloc/include/jemalloc", + "//third_party/FreeBSD/contrib/libexecinfo", ] } @@ -333,25 +334,43 @@ template("musl_libs") { source_set("soft_musl_src") { sources_orig = [] sources = [] - + include_dirs = [] sources_orig = musl_src_arch_file + musl_src_file + sources_orig -= musl_src_filterout sources_orig -= [ - "src/env/__stack_chk_fail.c", - "src/env/__libc_start_main.c", - "src/env/__init_tls.c", - "src/string/memset.c", "src/string/mempcpy.c", + "src/string/memset.c", + "src/env/__init_tls.c", + "src/env/__libc_start_main.c", + "src/env/__stack_chk_fail.c", "src/stdlib/qsort.c", "src/stdlib/qsort_nr.c", - ] - if (musl_arch == "mips") { - sources_orig += [ "src/string/memset.c" ] - } - sources_orig -= musl_src_filterout - - sources += [ - "$FREEBSD_DIR/contrib/tcp_wrappers/strcasecmp.c", - "$FREEBSD_DIR/lib/libc/stdlib/qsort.c", + "src/string/strncpy.c", + ] + + freebsd_files = [ + "//third_party/FreeBSD/contrib/gdtoa/strtod.c", + "//third_party/FreeBSD/contrib/gdtoa/gethex.c", + "//third_party/FreeBSD/contrib/gdtoa/smisc.c", + "//third_party/FreeBSD/contrib/gdtoa/misc.c", + "//third_party/FreeBSD/contrib/gdtoa/strtord.c", + "//third_party/FreeBSD/contrib/gdtoa/hexnan.c", + "//third_party/FreeBSD/contrib/gdtoa/gmisc.c", + "//third_party/FreeBSD/contrib/gdtoa/hd_init.c", + "//third_party/FreeBSD/contrib/gdtoa/strtodg.c", + "//third_party/FreeBSD/contrib/gdtoa/ulp.c", + "//third_party/FreeBSD/contrib/gdtoa/strtof.c", + "//third_party/FreeBSD/contrib/gdtoa/sum.c", + "//third_party/FreeBSD/lib/libc/gdtoa/glue.c", + "//third_party/FreeBSD/lib/libc/stdio/parsefloat.c", + "//third_party/FreeBSD/contrib/tcp_wrappers/strcasecmp.c", + "//third_party/FreeBSD/lib/libc/gen/arc4random.c", + "//third_party/FreeBSD/lib/libc/gen/arc4random_uniform.c", + "//third_party/FreeBSD/lib/libc/stdlib/qsort.c", + "//third_party/FreeBSD/lib/libc/stdlib/strtoimax.c", + "//third_party/FreeBSD/lib/libc/stdlib/strtoul.c", + "//third_party/FreeBSD/lib/libc/stdlib/strtoumax.c", + "//third_party/musl/third_party/openbsd/lib/libc/string/strncpy.c", ] if (musl_arch == "arm") { @@ -382,6 +401,7 @@ template("musl_libs") { "src/math/powl.c", "src/math/sinf.c", "src/math/cosf.c", + "src/linux/flock.c", ] } else if (musl_arch == "aarch64") { sources_orig -= [ @@ -416,12 +436,23 @@ template("musl_libs") { "src/math/sincos.c", "src/math/pow.c", "src/math/powf.c", + "src/linux/flock.c", ] } else if (musl_arch == "x86_64") { - sources_orig -= [ "src/thread/${musl_arch}/__set_thread_area.s" ] + sources_orig -= [ + "src/thread/${musl_arch}/__set_thread_area.s", + "src/linux/flock.c", + ] } defines = [] + defines += [ "FEATURE_ICU_LOCALE" ] + + # There are two ways to implement cxa_thread_atexit_impl: + # - CXA_THREAD_USE_TSD(default): use pthread_key_xxx to implement cxa_thread_atexit_impl. + # - CXA_THREAD_USE_TLS: put dtors in pthread to implement cxa_thread_atexit_impl. + defines += [ "CXA_THREAD_USE_TSD" ] + if (musl_arch == "arm") { defines += [ "MUSL_ARM_ARCH" ] } @@ -477,8 +508,7 @@ template("musl_libs") { "$OPTRTDIR/string/arm/strcmp.S", "$OPTRTDIR/string/arm/strlen-armv6t2.S", ] - - sources += added_freebsd_files + sources += freebsd_files asmflags = [ "-D__memcpy_arm = memcpy", "-D__memchr_arm = memchr", @@ -487,6 +517,7 @@ template("musl_libs") { "-D__strlen_armv6t2 = strlen", ] } else if (musl_arch == "aarch64") { + sources += freebsd_files if (defined(ARM_FEATURE_SVE)) { sources += [ "$OPTRTDIR/string/aarch64/memchr-sve.S", @@ -565,7 +596,6 @@ template("musl_libs") { "$OPTRTDIR/string/aarch64/strnlen.S", "$OPTRTDIR/string/aarch64/strrchr.S", ] - sources += added_freebsd_files asmflags = [ "-D__memmove_aarch64 = memmove", "-D__memcpy_aarch64 = memcpy", @@ -588,37 +618,19 @@ template("musl_libs") { cflags = [ "-O3", "-fPIC", - "-ffreestanding", "-fstack-protector-strong", - "-flto", ] - if (use_jemalloc) { - defines += [ "USE_JEMALLOC" ] - if (use_jemalloc_dfx_intf) { - defines += [ "USE_JEMALLOC_DFX_INTF" ] - } - include_dirs = [ "//third_party/jemalloc/include/jemalloc" ] - } - - if (!defined(include_dirs)) { - if (musl_arch == "aarch64") { - include_dirs = [ "//third_party/FreeBSD/lib/libc/aarch64" ] - } - if (musl_arch == "arm") { - include_dirs = [ "//third_party/FreeBSD/lib/libc/arm" ] - } - } else { - if (musl_arch == "aarch64") { - include_dirs += [ "//third_party/FreeBSD/lib/libc/aarch64" ] - } - if (musl_arch == "arm") { - include_dirs += [ "//third_party/FreeBSD/lib/libc/arm" ] - } - } - configs -= musl_inherited_configs configs += [ ":soft_musl_config" ] + if (musl_arch == "aarch64") { + include_dirs += [ "//third_party/FreeBSD/lib/libc/aarch64" ] + } else if (musl_arch == "arm") { + include_dirs += [ "//third_party/FreeBSD/lib/libc/arm" ] + } + include_dirs += [ "//third_party/FreeBSD/lib/libc/include" ] + include_dirs += [ "//third_party/FreeBSD/contrib/libexecinfo" ] + include_dirs += [ "//third_party/FreeBSD/crypto/openssh/openbsd-compat" ] if (!defined(defines)) { defines = [] @@ -633,7 +645,8 @@ template("musl_libs") { defines += [ "TARGET_GUARD_SIZE=${_product_config.device_guard_size}" ] } } - + external_deps = [] + external_deps += [ "FreeBSD:libc_static" ] deps = porting_deps } @@ -827,6 +840,8 @@ template("musl_libs") { ":soft_musl_src_nossp", ":soft_musl_src_optimize", ] + external_deps = [] + external_deps = [ "FreeBSD:libc_static" ] output_name = "libc" complete_static_lib = true } diff --git a/build/third_party_gn/openssl/BUILD.gn b/build/third_party_gn/openssl/BUILD.gn index 0b311628d66d8c7ea64c6fe3e95da9d81b267c9c..cae0e8ea69d4ef5c96eb868b3671c7ee6ae3b524 100644 --- a/build/third_party_gn/openssl/BUILD.gn +++ b/build/third_party_gn/openssl/BUILD.gn @@ -636,6 +636,10 @@ libdefault_common_sources = [ "//third_party/openssl/providers/implementations/ciphers/cipher_cts.c", "//third_party/openssl/providers/implementations/ciphers/cipher_null.c", "//third_party/openssl/providers/implementations/ciphers/cipher_sm4.c", + "//third_party/openssl/providers/implementations/ciphers/cipher_sm4_ccm.c", + "//third_party/openssl/providers/implementations/ciphers/cipher_sm4_ccm_hw.c", + "//third_party/openssl/providers/implementations/ciphers/cipher_sm4_gcm.c", + "//third_party/openssl/providers/implementations/ciphers/cipher_sm4_gcm_hw.c", "//third_party/openssl/providers/implementations/ciphers/cipher_sm4_hw.c", "//third_party/openssl/providers/implementations/ciphers/cipher_tdes.c", "//third_party/openssl/providers/implementations/ciphers/cipher_tdes_common.c", diff --git a/inspector/BUILD.gn b/inspector/BUILD.gn index 48d5efabb79bb86f6d49da2be4f0e36fa7716d71..ed21732614f9decd6f01e42641b8cf13ecb437c3 100644 --- a/inspector/BUILD.gn +++ b/inspector/BUILD.gn @@ -69,6 +69,7 @@ ohos_shared_library("ark_debugger") { innerapi_tags = [ "platformsdk" ] subsystem_name = "arkcompiler" part_name = "toolchain" + output_name = "ark_inspector" } ohos_source_set("connectserver_debugger_static") { @@ -118,4 +119,5 @@ ohos_shared_library("connectserver_debugger") { innerapi_tags = [ "platformsdk" ] subsystem_name = "arkcompiler" part_name = "toolchain" + output_name = "ark_connect_inspector" } diff --git a/inspector/connect_inspector.cpp b/inspector/connect_inspector.cpp index 200d2842bc081437fe47a030c1b10cfafd2476be..3c4ef11bfcae44e0111c3796683ee45dc53cd633 100644 --- a/inspector/connect_inspector.cpp +++ b/inspector/connect_inspector.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 Huawei Device Co., Ltd. + * Copyright (c) 2023-2024 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at @@ -26,6 +26,8 @@ static constexpr char REQUEST_MESSAGE[] = "tree"; static constexpr char STOPDEBUGGER_MESSAGE[] = "stopDebugger"; static constexpr char OPEN_ARKUI_STATE_PROFILER[] = "ArkUIStateProfilerOpen"; static constexpr char CLOSE_ARKUI_STATE_PROFILER[] = "ArkUIStateProfilerClose"; +static constexpr char START_RECORD_MESSAGE[] = "rsNodeStartRecord"; +static constexpr char STOP_RECORD_MESSAGE[] = "rsNodeStopRecord"; std::function g_setConnectCallBack; void* HandleDebugManager(void* const server) @@ -67,6 +69,25 @@ void OnOpenMessage(const std::string& message) } } +void OnInspectorRecordMessage(const std::string& message) +{ + if (message.find(START_RECORD_MESSAGE, 0) != std::string::npos) { + if (g_inspector->startRecord_ != nullptr && !g_inspector->isRecording_) { + LOGI("record start"); + g_inspector->startRecord_(); + g_inspector->isRecording_ = true; + } + } + + if (message.find(STOP_RECORD_MESSAGE, 0) != std::string::npos) { + if (g_inspector->stopRecord_ != nullptr && g_inspector->isRecording_) { + LOGI("record stop"); + g_inspector->stopRecord_(); + g_inspector->isRecording_ = false; + } + } +} + void OnMessage(const std::string& message) { std::lock_guard lock(g_connectMutex); @@ -115,6 +136,7 @@ void OnMessage(const std::string& message) g_inspector->setDebugMode_(); } } + OnInspectorRecordMessage(message); } } @@ -152,12 +174,16 @@ void ResetService() } } -void StartServerForSocketPair(int socketfd) +bool StartServerForSocketPair(int socketfd) { LOGI("StartServerForSocketPair, socketfd = %{private}d", socketfd); if (g_inspector == nullptr) { g_inspector = std::make_unique(); } + if (g_inspector->connectServer_ != nullptr) { + LOGW("ConnectServer is not nullptr!"); + return false; + } g_inspector->connectServer_ = std::make_unique(socketfd, std::bind(&OnMessage, std::placeholders::_1)); @@ -166,8 +192,9 @@ void StartServerForSocketPair(int socketfd) static_cast(g_inspector->connectServer_.get())) != 0) { LOGE("pthread_create fail!"); ResetService(); - return; + return false; } + return true; } void StartServer(const std::string& componentName) @@ -269,4 +296,14 @@ void SetProfilerCallback(const std::function &setArkUIStateProfilerS g_inspector->setArkUIStateProfilerStatus_ = setArkUIStateProfilerStatus; } +void SetRecordCallback(const std::function &startRecordFunc, + const std::function &stopRecordFunc) +{ + std::lock_guard lock(g_connectMutex); + if (g_inspector == nullptr) { + g_inspector = std::make_unique(); + } + g_inspector->startRecord_ = startRecordFunc; + g_inspector->stopRecord_ = stopRecordFunc; +} } // OHOS::ArkCompiler::Toolchain diff --git a/inspector/connect_inspector.h b/inspector/connect_inspector.h index 4225304f53635762659b4d854707e32914a2072f..acb9b62d7c1914ce6cc75f9148bf08a01fea521b 100644 --- a/inspector/connect_inspector.h +++ b/inspector/connect_inspector.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 Huawei Device Co., Ltd. + * Copyright (c) 2023-2024 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at @@ -32,7 +32,7 @@ extern "C" { void StartServer(const std::string& componentName); // socketpair process. -void StartServerForSocketPair(int socketfd); +bool StartServerForSocketPair(int socketfd); void StopServer([[maybe_unused]] const std::string& componentName); @@ -59,6 +59,9 @@ void SetSwitchCallBack(const std::function& setSwitchStatus, void SetProfilerCallback(const std::function &setArkUIStateProfilerStatus); +void SetRecordCallback(const std::function &startRecordFunc, + const std::function &stopRecordFunc); + #ifdef __cplusplus #if __cplusplus } @@ -86,6 +89,9 @@ public: std::function createLayoutInfo_; std::function setDebugMode_; int32_t instanceId_ = -1; + std::function startRecord_; + std::function stopRecord_; + bool isRecording_ = false; }; } // namespace OHOS::ArkCompiler::Toolchain diff --git a/inspector/inspector.cpp b/inspector/inspector.cpp index 3292a9d69516935844c2fef9f08a2a52f7d95d26..030dbddecd2278b28dad8c3e41078af68d1ead0c 100644 --- a/inspector/inspector.cpp +++ b/inspector/inspector.cpp @@ -71,11 +71,11 @@ thread_local void* g_vm = nullptr; #if !defined(IOS_PLATFORM) #if defined(WINDOWS_PLATFORM) -constexpr char ARK_DEBUGGER_SHARED_LIB[] = "libark_ecma_debugger.dll"; +constexpr char ARK_DEBUGGER_SHARED_LIB[] = "libark_tooling.dll"; #elif defined(MAC_PLATFORM) -constexpr char ARK_DEBUGGER_SHARED_LIB[] = "libark_ecma_debugger.dylib"; +constexpr char ARK_DEBUGGER_SHARED_LIB[] = "libark_tooling.dylib"; #else -constexpr char ARK_DEBUGGER_SHARED_LIB[] = "libark_ecma_debugger.so"; +constexpr char ARK_DEBUGGER_SHARED_LIB[] = "libark_tooling.so"; #endif #endif @@ -150,18 +150,15 @@ bool InitializeInspector( void* vm, const DebuggerPostTask& debuggerPostTask, const DebugInfo& debugInfo, int tidForSocketPair = 0) { std::unique_lock lock(g_mutex); - Inspector *newInspector = nullptr; auto iter = g_inspectors.find(vm); if (iter != g_inspectors.end()) { - newInspector = g_inspectors[vm]; - } else { - newInspector = new Inspector(); - if (!g_inspectors.emplace(vm, newInspector).second) { - delete newInspector; - return false; - } + LOGW("Inspector already exist!"); + return true; } + Inspector *newInspector = new Inspector(); + g_inspectors.emplace(vm, newInspector); + newInspector->tidForSocketPair_ = tidForSocketPair; newInspector->tid_ = pthread_self(); newInspector->vm_ = vm; @@ -303,14 +300,16 @@ void Inspector::OnMessage(std::string&& msg) #if defined(OHOS_PLATFORM) uint64_t Inspector::GetThreadOrTaskId() { - uint64_t threadOrTaskId = static_cast(getproctid()); #if defined(ENABLE_FFRT_INTERFACES) - threadOrTaskId = ffrt_this_task_get_id(); - if (threadOrTaskId == 0) { - threadOrTaskId = static_cast(getproctid()); + uint64_t threadOrTaskId = ffrt_this_task_get_id(); + if (threadOrTaskId != 0) { + return threadOrTaskId; + } else { + return static_cast(getproctid()); } +#else + return static_cast(getproctid()); #endif // defined(ENABLE_FFRT_INTERFACES) - return threadOrTaskId; } #endif // defined(OHOS_PLATFORM) diff --git a/inspector/test/BUILD.gn b/inspector/test/BUILD.gn new file mode 100644 index 0000000000000000000000000000000000000000..4153eb438535faba525b090d29df14adaf56d7a9 --- /dev/null +++ b/inspector/test/BUILD.gn @@ -0,0 +1,69 @@ +# Copyright (c) 2024 Huawei Device Co., Ltd. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import("//arkcompiler/toolchain/test/test_helper.gni") +import("//arkcompiler/toolchain/toolchain.gni") + +module_output_path = "arkcompiler/toolchain" + +host_unittest_action("InspectorConnectTest") { + module_out_path = module_output_path + + include_dirs = [ "$toolchain_root/inspector" ] + + sources = [ + # test file + "connect_server_test.cpp", + ] + + configs = [ "$toolchain_root:toolchain_test_config" ] + + deps = [ + "$toolchain_root/inspector:connectserver_debugger", + "$toolchain_root/websocket:websocket_client", + "$toolchain_root/websocket:websocket_server", + ] + + # hiviewdfx libraries + external_deps = hiviewdfx_ext_deps + if (is_arkui_x && target_os == "ios") { + external_deps += [ "openssl:libcrypto_static" ] + } else { + external_deps += [ "openssl:libcrypto_shared" ] + } + + external_deps += [ "bounds_checking_function:libsec_shared" ] + deps += hiviewdfx_deps +} + +group("unittest") { + testonly = true + + # deps file + deps = [ ":InspectorConnectTest" ] + + if (is_mac) { + deps -= [ ":InspectorConnectTest" ] + } +} + +group("host_unittest") { + testonly = true + + # deps file + deps = [ ":InspectorConnectTestAction" ] + + if (is_mac) { + deps -= [ ":InspectorConnectTestAction" ] + } +} diff --git a/inspector/test/connect_server_test.cpp b/inspector/test/connect_server_test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..097ee229b8fd900c19540b40fd1fc41d3d9e1934 --- /dev/null +++ b/inspector/test/connect_server_test.cpp @@ -0,0 +1,175 @@ +/* + * Copyright (c) 2024 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "gtest/gtest.h" +#include "inspector/connect_inspector.h" +#include "inspector/connect_server.h" +#include "websocket/client/websocket_client.h" +#include "websocket/server/websocket_server.h" + +using namespace OHOS::ArkCompiler::Toolchain; + +namespace panda::test { +class ConnectServerTest : public testing::Test { +public: + static void SetUpTestCase() + { + GTEST_LOG_(INFO) << "ConnectServerTest::SetUpTestCase"; + } + + static void TearDownTestCase() + { + GTEST_LOG_(INFO) << "ConnectServerTest::TearDownTestCase"; + } + + void SetUp() override {} + + void TearDown() override {} + void ReturnValueVerification(); +#if defined(OHOS_PLATFORM) + static constexpr char CONNECTED_MESSAGE_TEST[] = "connected"; + static constexpr char OPEN_MESSAGE_TEST[] = "layoutOpen"; + static constexpr char CLOSE_MESSAGE_TEST[] = "layoutClose"; + static constexpr char REQUEST_MESSAGE_TEST[] = "tree"; + static constexpr char STOPDEBUGGER_MESSAGE_TEST[] = "stopDebugger"; + static constexpr char OPEN_ARKUI_STATE_PROFILER_TEST[] = "ArkUIStateProfilerOpen"; + static constexpr char CLOSE_ARKUI_STATE_PROFILER_TEST[] = "ArkUIStateProfilerClose"; + static constexpr char START_RECORD_MESSAGE_TEST[] = "rsNodeStartRecord"; + static constexpr char STOP_RECORD_MESSAGE_TEST[] = "rsNodeStopRecord"; + + static constexpr char HELLO_INSPECTOR_CLIENT[] = "hello inspector client"; + static constexpr char INSPECTOR_SERVER_OK[] = "inspector server ok"; + static constexpr char INSPECTOR_RUN[] = "inspector run"; + static constexpr char INSPECTOR_QUIT[] = "inspector quit"; + static constexpr int32_t WAIT_TIME = 2; +#endif +}; + +bool g_profilerFlag = false; +bool g_connectFlag = false; +bool g_switchStatus = false; +int32_t g_createInfoId = 0; +int32_t g_instanceId = 1; + +void CallbackInit() +{ + auto profilerCb = [](bool flag) -> void { + g_profilerFlag = flag; + }; + SetProfilerCallback(profilerCb); + + auto connectCb = [](bool flag) -> void { + g_connectFlag = flag; + }; + SetConnectCallback(connectCb); + + auto debugModeCb = []() -> void { + GTEST_LOG_(INFO) << "Execute DebugModeCallBack."; + }; + SetDebugModeCallBack(debugModeCb); + + auto switchStatusCb = [](bool flag) -> void { + g_switchStatus = flag; + }; + auto createInfoCb = [](int32_t id) -> void { + g_createInfoId = id; + }; + SetSwitchCallBack(switchStatusCb, createInfoCb, g_instanceId); + + auto startRecordFunc = []() -> void {}; + auto stopRecordFunc = []() -> void {}; + SetRecordCallback(startRecordFunc, stopRecordFunc); + GTEST_LOG_(INFO) << "ConnectServerTest::CallbackInit finished"; +} + +void ConnectServerTest::ReturnValueVerification() +{ +#if defined(OHOS_PLATFORM) + // Waiting for executing the message instruction sent by the client + sleep(WAIT_TIME); + ASSERT_TRUE(g_profilerFlag); + ASSERT_EQ(g_createInfoId, g_instanceId); + ASSERT_TRUE(g_switchStatus); + ASSERT_TRUE(g_connectFlag); + ASSERT_FALSE(WaitForConnection()); + + SendMessage(INSPECTOR_SERVER_OK); + SendLayoutMessage(INSPECTOR_RUN); + + // Waiting for executing the message instruction sent by the client + sleep(WAIT_TIME); + ASSERT_FALSE(g_profilerFlag); + ASSERT_FALSE(g_switchStatus); + ASSERT_FALSE(g_connectFlag); + + SendProfilerMessage(INSPECTOR_QUIT); + + StopServer("InspectorConnectTest"); +#endif +} + +HWTEST_F(ConnectServerTest, InspectorBasicTest, testing::ext::TestSize.Level0) +{ + ASSERT_TRUE(WaitForConnection()); +} + +HWTEST_F(ConnectServerTest, InspectorConnectTest, testing::ext::TestSize.Level0) +{ + CallbackInit(); +#if defined(OHOS_PLATFORM) + int appPid = getprocpid(); + int oldProcessfd = -2; + ASSERT_TRUE(StartServerForSocketPair(oldProcessfd)); + // test ConnectServer is not nullptr + ASSERT_FALSE(StartServerForSocketPair(oldProcessfd)); + StoreMessage(g_instanceId, HELLO_INSPECTOR_CLIENT); + pid_t pid = fork(); + if (pid == 0) { + WebSocketClient clientSocket; + ASSERT_TRUE(clientSocket.InitToolchainWebSocketForSockName(std::to_string(appPid))); + ASSERT_TRUE(clientSocket.ClientSendWSUpgradeReq()); + ASSERT_TRUE(clientSocket.ClientRecvWSUpgradeRsp()); + EXPECT_TRUE(clientSocket.SendReply(OPEN_ARKUI_STATE_PROFILER_TEST)); + EXPECT_TRUE(clientSocket.SendReply(REQUEST_MESSAGE_TEST)); + EXPECT_TRUE(clientSocket.SendReply(OPEN_MESSAGE_TEST)); + EXPECT_TRUE(clientSocket.SendReply(CONNECTED_MESSAGE_TEST)); + EXPECT_TRUE(clientSocket.SendReply(START_RECORD_MESSAGE_TEST)); + EXPECT_TRUE(clientSocket.SendReply(STOP_RECORD_MESSAGE_TEST)); + + EXPECT_STREQ(clientSocket.Decode().c_str(), HELLO_INSPECTOR_CLIENT); + + std::string recv = clientSocket.Decode(); + EXPECT_STREQ(recv.c_str(), INSPECTOR_SERVER_OK); + if (strcmp(recv.c_str(), INSPECTOR_SERVER_OK) == 0) { + EXPECT_TRUE(clientSocket.SendReply(CLOSE_MESSAGE_TEST)); + EXPECT_TRUE(clientSocket.SendReply(STOPDEBUGGER_MESSAGE_TEST)); + EXPECT_TRUE(clientSocket.SendReply(CLOSE_ARKUI_STATE_PROFILER_TEST)); + } + + EXPECT_STREQ(clientSocket.Decode().c_str(), INSPECTOR_RUN); + EXPECT_STREQ(clientSocket.Decode().c_str(), INSPECTOR_QUIT); + clientSocket.Close(); + exit(0); + } else if (pid > 0) { + ReturnValueVerification(); + } + else { + std::cerr << "InspectorConnectTest::fork failed" << std::endl; + } + RemoveMessage(g_instanceId); +#endif +} + +} // namespace panda::test \ No newline at end of file diff --git a/test/autotest/README.md b/test/autotest/README.md new file mode 100644 index 0000000000000000000000000000000000000000..3d7e3b06e960e52b5a691e8a356f19cacbb3b2e1 --- /dev/null +++ b/test/autotest/README.md @@ -0,0 +1,239 @@ +# 调试调优自动化测试框架使用指南 + +[TOC] + +## 1 框架设计 + +调试调优的通用流程可抽象为如下步骤: + +- IDE将应用推入设备,并拉起应用(或attach到已启动应用上) + +- IDE与应用建立websocket连接 +- IDE与应用之间通过websocket发送和接受调试调优相关的业务消息,消息格式遵循CDP协议 + +该自动化框架依据以上流程,实现了应用启动、websocket连接、消息交互等步骤的自动化,基于此可以进行调试调优用例的执行与开发 + +框架的目录结构与功能描述如下: + +### aw + +封装了自动化框架通用的Action Words,包括: + +- `application.py`:应用启动、停止、安装、卸载等相关接口 +- `fport.py`:执行hdc fport命令的相关接口,指定端口号、进程ID和线程ID等,用于后续的websocket连接 +- `utils.py`:封装各种通用的工具类接口 +- `websocket.py`:websocket连接的关键基础类,功能包括: + - connect server和debugger server的websocket连接 + - 采用消息队列实现websocket的消息发送与接收 + - **支持多实例应用的实现**:connect server的消息接收队列持续监听addInstance消息,一旦接收到新的instance后,便会创建对应的debugger server连接 + - **异步实现**:多条websocket连接的消息接收与发送通道均实现为协程,可被提交到taskpool中作为异步任务执行 +- `taskpool.py`:异步任务池,功能包括: + - 采用队列实现任务池的生命周期控制 + - **可在任意时刻提交任务到taskpool中进行异步执行** + - 可为每个任务添加任意多个回调函数,在任务结束后执行 +- `cdp`:cdp协议的封装 + +### scenario_test + +场景测试用例目录 + +- `conftest.py`:基于pytest fixture实现的测试套方法 +- `test_name_number.py`:测试用例文件 + +### resource + +用于放置编译后的应用hap包 + +目录下的archive.json记录了应用工程名、hap包名和bundle name的对应关系 + +### pytest.ini + +python pytest库的配置文件 + +### run.py + +批量执行测试用例的入口文件 + +### requirements.txt + +自动化测试框架的python库依赖 + +## 2 测试用例执行 + +### 准备工作 + +- 操作系统为Windows + +- 已安装hdc.exe并配置好环境变量,可通过cmd启动执行 + +- 测试设备已连接,且开启USB调试 + +- 下载自动化测试项目 + + 代码仓:https://gitee.com/openharmony/arkcompiler_toolchain + + 项目目录:`.\arkcompiler_toolchain\test\autotest` + +- Python已安装且版本 >= 3.8.0 + +- 安装Python依赖 + + ```powershell + > cd .\arkcompiler_toolchain\test\autotest + > python -m pip install -r requirements.txt [--trusted-host hostname -i Python_Package_Index] + ``` + +- 下载hap包 + + 通过归档链接下载hap包,并将所有hap包移动到.\arkcompiler_toolchain\test\autotest\resource目录下 + +### 执行用例 + +cmd进入`.\arkcompiler_toolchain\test\autotest`目录,执行: + +```python +> python .\run.py +``` + +用例执行过程中,cmd会实时输出用例日志信息,执行完成后,cmd会展示执行结果,同时会生成测试报告,并导出hilog日志: + +- `.\arkcompiler_toolchain\test\autotest\report\report.html`:测试报告 + +- `.\arkcompiler_toolchain\test\autotest\report\xxx.hilog.txt`:每个测试用例对应一份debug级别的hilog日志 + +- `.\arkcompiler_toolchain\test\autotest\report\faultlogger`:用例执行过程中产生的错误日志 + +## 3 测试用例开发 + +### 测试应用 + +根据测试用例场景,确定并开发你的测试应用,编译后将应用hap包放在`.\arkcompiler_toolchain\test\autotest\resource`目录下 + +### 测试套 + +测试套以pytest fixture形式开发,对应于`.\arkcompiler_toolchain\test\autotest\scenario_test\conftest.py`中的一个方法; + +对于一个确定的测试应用,和一套固定的配置信息,我们可以将他们抽象出来作为一个fixture,基于该fixture我们可以开发多个测试用例 + +fixture写法举例如下: + +```python +@pytest.fixture(scope='class') # 该装饰器指定下面的函数是一个fixture +def test_suite_debug_01(): # fixture名称 + logging.info('running test_suite_debug_01') + + bundle_name = 'com.example.worker' + hap_name = 'MyApplicationWorker.hap' + + config = {'connect_server_port': 15678, + 'debugger_server_port': 15679, + 'bundle_name': bundle_name, + 'hap_path': rf'{os.path.dirname(__file__)}\..\resource\{hap_name}'} + + # 将应用推入设备,并以-D模式启动 + pid = Application.launch_application(config['bundle_name'], config['hap_path'], start_mode='-D') + assert pid != 0, logging.error(f'Pid of {hap_name} is 0!') + config['pid'] = pid + + # hdc fport + Fport.clear_fport() + Fport.fport_connect_server(config['connect_server_port'], config['pid'], config['bundle_name']) + + # 实例化WebSocket对象 + config['websocket'] = WebSocket(config['connect_server_port'], config['debugger_server_port']) + + # 实例化TaskPool对象 + config['taskpool'] = TaskPool() + + return config + +``` + +样例参考:`.\arkcompiler_toolchain\test\autotest\scenario_test\conftest.py => test_suite_debug_01` + +### 测试用例 + +测试用例放置在`.\arkcompiler_toolchain\test\autotest\scenario_test\`目录下,每个.py文件对应一个测试用例,命名规则为`test\_测试项\_编号.py` + +测试用例代码文件结构如下: + +```python +@pytest.mark.debug +@pytest.mark.timeout(40) +class TestDebug01: + def setup_method(self): + pass + + def teardown_method(self): + pass + + def test(self, test_suite_debug_01): + pass + + async def procedure(self, websocket): + pass + +``` + +- 装饰器`@pytest.mark.debug`标明该用例是一个测试debug功能的用例,debug可以改为其它任意名字,如cpu_profiler + +- 装饰器`@pytest.mark.timeout(40)`标明该用例必须在40s内执行完毕,否则不通过 + +- `class TestDebug01` 是该测试用例对应的测试类,测试类必须以**Test**开头 + +- `setup_class` 方法在用例开始执行前被执行,其中放置一些需要初始化的内容 + +- `teardown_clas` 方法在用例结束执行后被执行,其中放置一些需要结束或清理的内容 + +- `test` 方法是测试用例执行的入口,注意以下几点: + + - 第二个参数为fixture,不仅可以标识该用例属于哪个测试套,还可以获取该fixture执行后的返回结果;在test方法被执行前,fixture会首先被执行 + + - 通过下面的代码,将websocket中封装的main task提交到taskpool,等待所有任务结束并捕获异常 + + ```Python + taskpool.submit(websocket.main_task(taskpool, websocket, self.procedure, pid)) + taskpool.await_taskpool() + taskpool.task_join() + if taskpool.task_exception: + raise taskpool.task_exception + ``` + +- **`procedure`方法**:测试步骤和预期结果执行的位置,在test方法中,procedure作为参数被提交到taskpool中,因此其同样作为一个**异步任务**在执行 + +当我们新增一个测试用例时,主要工作就是在procedure方法中放置我们的测试步骤和预期结果。首先,我们可以手动执行一次测试用例,并抓出connect server、debugger server交互的日志信息。此后,我们可以对照日志信息在procedure方法中添加内容,每一次消息发送可以当作一个测试步骤,每一次消息接收可以当作一次预期结果 + +例如: + +```Python +################################################################################################################ +# main thread: Debugger.getPossibleAndSetBreakpointByUrl +################################################################################################################ +id = next(self.id_generator) # 获取此次发送消息的id + +# 构造断点信息 +locations = [debugger.BreakLocationUrl(url='entry|entry|1.0.0|src/main/ets/pages/Index.ts', line_number=22), + debugger.BreakLocationUrl(url='entry|entry|1.0.0|src/main/ets/pages/Index.ts', line_number=26)] + +# 发送消息并获取返回值,调用cdp库中的debugger.get_possible_and_set_breakpoint_by_url(locations)可以自动拼接cdp消息 +response = await communicate_with_debugger_server(main_thread_instance_id, + main_thread_to_send_queue, + main_thread_received_queue, + debugger.get_possible_and_set_breakpoint_by_url(locations), + id) + +# 判断返回结果是否符合预期 +response = json.loads(response) +assert response['id'] == id +assert response['result']['locations'][0]['id'] == 'id:22:0:entry|entry|1.0.0|src/main/ets/pages/Index.ts' +assert response['result']['locations'][1]['id'] == 'id:26:0:entry|entry|1.0.0|src/main/ets/pages/Index.ts' +``` + +注意: + +- 建议在测试类声明后,用类注释写明该测试用例的内容; +- 每个测试步骤和预期结果之间,用上述注释方式隔开,并标明此次测试步骤的操作; +- 对于aw中未实现的CDP协议,请封装在aw/cdp目录下对应的domain文件中 + +样例参考:`.\arkcompiler_toolchain\test\autotest\scenario_test\test_debug_01.py` + diff --git a/test/autotest/aw/__init__.py b/test/autotest/aw/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..50005d3837a7d825fbbf51da0ade8abd2a31fb09 --- /dev/null +++ b/test/autotest/aw/__init__.py @@ -0,0 +1,31 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +""" +Copyright (c) 2024 Huawei Device Co., Ltd. +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +Description: __init__.py of the aw package +""" +from aw.websocket import WebSocket +from aw.application import Application +from aw.utils import Utils +from aw.fport import Fport +from aw.taskpool import TaskPool +from aw.cdp import debugger +from aw.cdp import runtime +from aw.cdp import heap_profiler +from aw.cdp import cpu_profiler + + +communicate_with_debugger_server = Utils.communicate_with_debugger_server +async_wait_timeout = Utils.async_wait_timeout \ No newline at end of file diff --git a/test/autotest/aw/api/debugger_api.py b/test/autotest/aw/api/debugger_api.py new file mode 100644 index 0000000000000000000000000000000000000000..d22cd0192cbc23aace95037221e2fe3a57624f94 --- /dev/null +++ b/test/autotest/aw/api/debugger_api.py @@ -0,0 +1,216 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +""" +Copyright (c) 2024 Huawei Device Co., Ltd. +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +Description: Python Debugger Domain Interfaces +""" + +import json +import logging +from http.client import responses + +from aw import communicate_with_debugger_server, Utils +from aw.cdp import debugger +from aw.types import ThreadConnectionInfo, ProtocolType + + +class DebuggerImpl(object): + + def __init__(self, id_generator): + self.dispatch_table = {"enable": (self.enable, ProtocolType.send), + "disable": (self.disable, ProtocolType.send), + "resume": (self.resume, ProtocolType.send), + "removeBreakpointsByUrl": (self.remove_breakpoints_by_url, ProtocolType.send), + "getPossibleAndSetBreakpointsByUrl": (self.get_possible_and_set_breakpoints_by_url, + ProtocolType.send), + "stepOver": (self.step_over, ProtocolType.send), + "stepInto": (self.step_into, ProtocolType.send), + "scriptParsed": (self.script_parsed, ProtocolType.recv), + "paused": (self.paused, ProtocolType.recv), + "stepOut": (self.step_out, ProtocolType.send)} + self.id_generator = id_generator + + @classmethod + async def connect_to_debugger_server(cls, websocket, pid, is_main=True): + if is_main: + send_msg = {"type": "connected"} + await websocket.send_msg_to_connect_server(send_msg) + response = await websocket.recv_msg_of_connect_server() + response = json.loads(response) + assert response['type'] == 'addInstance' + assert response['instanceId'] == 0, logging.error('InstanceId of the main thread is not 0') + assert response['tid'] == pid + else: + response = await websocket.recv_msg_of_connect_server() + response = json.loads(response) + assert response['type'] == 'addInstance' + assert response['instanceId'] != 0 + assert response['tid'] != pid + assert 'workerThread_' in response['name'] + instance_id = await websocket.get_instance() + send_queue = websocket.to_send_msg_queues[instance_id] + recv_queue = websocket.received_msg_queues[instance_id] + connection = ThreadConnectionInfo(instance_id, send_queue, recv_queue) + return connection + + @classmethod + async def destroy_instance(cls, websocket): + response = await websocket.recv_msg_of_connect_server() + response = json.loads(response) + return response + + @classmethod + async def enable(cls, message_id, connection, websocket, params=None): + response = await communicate_with_debugger_server(connection.instance_id, + connection.send_msg_queue, + connection.received_msg_queue, + debugger.enable(), message_id) + while response.startswith('{"method":"Debugger.scriptParsed"'): + response = await websocket.recv_msg_of_debugger_server(connection.instance_id, + connection.received_msg_queue) + response = json.loads(response) + assert response == {"id": message_id, "result": {"debuggerId": "0", "protocols": Utils.get_custom_protocols()}} + + @classmethod + async def disable(cls, message_id, connection, websocket, params=None): + response = await communicate_with_debugger_server(connection.instance_id, + connection.send_msg_queue, + connection.received_msg_queue, + debugger.disable(), message_id) + assert json.loads(response) == {"method": "Debugger.resumed", "params": {}} + response = await websocket.recv_msg_of_debugger_server(connection.instance_id, + connection.received_msg_queue) + response = json.loads(response) + assert response == {"id": message_id, "result": {}} + return response + + @classmethod + async def script_parsed(cls, connection, websocket, params=None): + response = await websocket.recv_msg_of_debugger_server(connection.instance_id, + connection.received_msg_queue) + response = json.loads(response) + return response + + @classmethod + async def paused(cls, connection, websocket, params=None): + response = await websocket.recv_msg_of_debugger_server(connection.instance_id, + connection.received_msg_queue) + response = json.loads(response) + assert response['method'] == 'Debugger.paused' + return response + + @classmethod + async def resume(cls, message_id, connection, websocket, params=None): + response = await communicate_with_debugger_server(connection.instance_id, + connection.send_msg_queue, + connection.received_msg_queue, + debugger.resume(), message_id) + assert json.loads(response) == {"method": "Debugger.resumed", "params": {}} + response = await websocket.recv_msg_of_debugger_server(connection.instance_id, + connection.received_msg_queue) + response = json.loads(response) + assert response == {"id": message_id, "result": {}} + return response + + @classmethod + async def remove_breakpoints_by_url(cls, message_id, connection, websocket=None, params=None): + response = await communicate_with_debugger_server(connection.instance_id, + connection.send_msg_queue, + connection.received_msg_queue, + debugger.remove_breakpoints_by_url(params.url), message_id) + response = json.loads(response) + assert response == {"id": message_id, "result": {}} + return response + + @classmethod + async def get_possible_and_set_breakpoints_by_url(cls, message_id, connection, websocket=None, params=None): + response = await communicate_with_debugger_server(connection.instance_id, + connection.send_msg_queue, + connection.received_msg_queue, + debugger.get_possible_and_set_breakpoint_by_url(params.locations), + message_id) + response = json.loads(response) + assert response['id'] == message_id + return response + + @classmethod + async def step_over(cls, message_id, connection, websocket, params=None): + response = await communicate_with_debugger_server(connection.instance_id, + connection.send_msg_queue, + connection.received_msg_queue, + debugger.step_over(), message_id) + assert json.loads(response) == {"method": "Debugger.resumed", "params": {}} + response = await websocket.recv_msg_of_debugger_server(connection.instance_id, + connection.received_msg_queue) + response = json.loads(response) + assert response == {"id": message_id, "result": {}} + return response + + @classmethod + async def step_out(cls, message_id, connection, websocket, params=None): + response = await communicate_with_debugger_server(connection.instance_id, + connection.send_msg_queue, + connection.received_msg_queue, + debugger.step_out(), message_id) + assert json.loads(response) == {"method": "Debugger.resumed", "params": {}} + response = await websocket.recv_msg_of_debugger_server(connection.instance_id, + connection.received_msg_queue) + response = json.loads(response) + assert response == {"id": message_id, "result": {}} + return response + + @classmethod + async def step_into(cls, message_id, connection, websocket, params=None): + response = await communicate_with_debugger_server(connection.instance_id, + connection.send_msg_queue, + connection.received_msg_queue, + debugger.step_into(), message_id) + assert json.loads(response) == {"method": "Debugger.resumed", "params": {}} + response = await websocket.recv_msg_of_debugger_server(connection.instance_id, + connection.received_msg_queue) + response = json.loads(response) + assert response == {"id": message_id, "result": {}} + return response + + async def send(self, protocol_name, connection, websocket, params=None): + protocol = self._check_and_parse_protocol(protocol_name) + if self.dispatch_table.get(protocol) is not None: + if self.dispatch_table.get(protocol)[1] != ProtocolType.send: + raise AssertionError("DebuggerImpl send ProtocolType inconsistent: Protocol {}, calling {}, should be {}" + .format(protocol_name, "send", self.dispatch_table.get(protocol)[1])) + message_id = next(self.id_generator) + return await self.dispatch_table.get(protocol)[0](message_id, connection, websocket, params) + + async def recv(self, protocol_name, connection, websocket, params=None): + protocol = self._check_and_parse_protocol(protocol_name) + if self.dispatch_table.get(protocol) is not None: + if self.dispatch_table.get(protocol)[1] != ProtocolType.recv: + raise AssertionError("DebuggerImpl recv ProtocolType inconsistent: Protocol {}, calling {}, should be {}" + .format(protocol_name, "recv", self.dispatch_table.get(protocol)[1])) + return await self.dispatch_table.get(protocol)[0](connection, websocket, params) + + def _check_and_parse_protocol(self, protocol_name): + res = protocol_name.split('.') + if len(res) != 2: + raise AssertionError("DebuggerImpl parse protocol name error: protocol_name {} is invalid" + .format(protocol_name)) + domain, protocol = res[0], res[1] + if domain != 'Debugger': + raise AssertionError("DebuggerImpl parse protocol name error: protocol_name {} has the wrong domain" + .format(protocol_name)) + if protocol not in self.dispatch_table: + raise AssertionError("DebuggerImpl parse protocol name error: protocol_name {} has not been defined" + .format(protocol_name)) + return protocol \ No newline at end of file diff --git a/test/autotest/aw/api/runtime_api.py b/test/autotest/aw/api/runtime_api.py new file mode 100644 index 0000000000000000000000000000000000000000..af6d00029cdb459e2ae16b0b31f737d3161253b9 --- /dev/null +++ b/test/autotest/aw/api/runtime_api.py @@ -0,0 +1,98 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +""" +Copyright (c) 2024 Huawei Device Co., Ltd. +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +Description: Python Runtime Domain Interfaces +""" + +import json + +from aw import communicate_with_debugger_server +from aw.cdp import runtime +from aw.types import ProtocolType + + +class RuntimeImpl(object): + + def __init__(self, id_generator): + self.dispatch_table = {"enable": (self.enable, ProtocolType.send), + "runIfWaitingForDebugger": (self.run_if_waiting_for_debugger, ProtocolType.send), + "getProperties": (self.get_properties, ProtocolType.send)} + self.id_generator = id_generator + + @classmethod + async def enable(cls, message_id, connection, params=None): + response = await communicate_with_debugger_server(connection.instance_id, + connection.send_msg_queue, + connection.received_msg_queue, + runtime.enable(), message_id) + response = json.loads(response) + assert response == {"id": message_id, "result": {"protocols": []}} + return response + + @classmethod + async def run_if_waiting_for_debugger(cls, message_id, connection, params=None): + response = await communicate_with_debugger_server(connection.instance_id, + connection.send_msg_queue, + connection.received_msg_queue, + runtime.run_if_waiting_for_debugger(), message_id) + response = json.loads(response) + assert response == {"id": message_id, "result": {}} + return response + + @classmethod + async def get_properties(cls, message_id, connection, params=None): + response = await communicate_with_debugger_server(connection.instance_id, + connection.send_msg_queue, + connection.received_msg_queue, + runtime.get_properties(object_id=params.object_id, + own_properties=params.own_properties, + accessor_properties_only=params.accessor_properties_only, + generate_preview=params.generate_preview), message_id) + response = json.loads(response) + assert response["id"] == message_id + return response + + async def send(self, protocol_name, connection, params=None): + protocol = self._check_and_parse_protocol(protocol_name) + if self.dispatch_table.get(protocol) is not None: + if self.dispatch_table.get(protocol)[1] != ProtocolType.send: + raise AssertionError("RuntimeImpl send ProtocolType inconsistent: Protocol {}, calling {}, should be {}" + .format(protocol_name, "send", self.dispatch_table.get(protocol)[1])) + message_id = next(self.id_generator) + return await self.dispatch_table.get(protocol)[0](message_id, connection, params) + + async def recv(self, protocol_name, connection, params=None): + protocol = self._check_and_parse_protocol(protocol_name) + if self.dispatch_table.get(protocol) is not None: + if self.dispatch_table.get(protocol)[1] != ProtocolType.recv: + raise AssertionError("RuntimeImpl recv ProtocolType inconsistent: Protocol {}, calling {}, should be {}" + .format(protocol_name, "recv", self.dispatch_table.get(protocol)[1])) + message_id = next(self.id_generator) + return await self.dispatch_table.get(protocol)[0](message_id, connection, params) + + def _check_and_parse_protocol(self, protocol_name): + res = protocol_name.split('.') + if len(res) != 2: + raise AssertionError("RuntimeImpl parse protocol name error: protocol_name {} is invalid" + .format(protocol_name)) + domain, protocol = res[0], res[1] + if domain != 'Runtime': + raise AssertionError("RuntimeImpl parse protocol name error: protocol_name {} has the wrong domain" + .format(protocol_name)) + if protocol not in self.dispatch_table: + raise AssertionError("RuntimeImpl parse protocol name error: protocol_name {} has not been defined" + .format(protocol_name)) + return protocol diff --git a/test/autotest/aw/application.py b/test/autotest/aw/application.py new file mode 100644 index 0000000000000000000000000000000000000000..2a9eca1d650edc40a8623913eea6d24b65f1c3dd --- /dev/null +++ b/test/autotest/aw/application.py @@ -0,0 +1,114 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +""" +Copyright (c) 2024 Huawei Device Co., Ltd. +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +Description: Action words of Application launch. +""" + +import logging +import subprocess +import re +import time + + +class Application(object): + @classmethod + def stop(cls, bundle_name): + stop_cmd = ['hdc', 'shell', 'aa', 'force-stop', bundle_name] + logging.info('force stop application: ' + ' '.join(stop_cmd)) + stop_result = subprocess.run(stop_cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + logging.info(stop_result.stdout.strip()) + assert stop_result.returncode == 0 + + @classmethod + def uninstall(cls, bundle_name): + uninstall_cmd = ['hdc', 'uninstall', bundle_name] + logging.info('uninstall application: ' + ' '.join(uninstall_cmd)) + uninstall_result = subprocess.run(uninstall_cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + logging.info(uninstall_result.stdout.strip()) + assert uninstall_result.returncode == 0 + + @classmethod + def install(cls, hap_path): + install_cmd = ['hdc', 'install', '-r', hap_path] + logging.info('install application: ' + ' '.join(install_cmd)) + install_result = subprocess.run(install_cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + logging.info(install_result.stdout) + assert 'successfully' in install_result.stdout.decode('utf-8') + + @classmethod + def start(cls, bundle_name, start_mode=None): + start_cmd = (['hdc', 'shell', 'aa', 'start', '-a', 'EntryAbility', '-b', bundle_name] + + ([start_mode] if start_mode else [])) + logging.info('start application: ' + ' '.join(start_cmd)) + start_result = subprocess.run(start_cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + logging.info(start_result.stdout) + assert start_result.stdout.decode('utf-8').strip() == 'start ability successfully.' + + @classmethod + def get_pid(cls, bundle_name): + ps_cmd = ['hdc', 'shell', 'ps', '-ef'] + ps_result = subprocess.run(ps_cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + ps_result_out = ps_result.stdout.decode('utf-8') + for line in ps_result_out.strip().split('\r\n'): + if bundle_name in line: + logging.info(f'pid of {bundle_name}: ' + line) + return line.strip().split()[1] + return 0 + + @classmethod + def launch_application(cls, bundle_name, hap_path, start_mode=None): + cls.stop(bundle_name) + cls.uninstall(bundle_name) + cls.install(hap_path) + cls.start(bundle_name, start_mode) + cls.keep_awake() + time.sleep(3) + pid = cls.get_pid(bundle_name) + return int(pid) + + @classmethod + def attach(cls, bundle_name): + attach_cmd = (['hdc', 'shell', 'aa', 'attach', '-b', bundle_name]) + logging.info('start application: ' + ' '.join(attach_cmd)) + attach_result = subprocess.run(attach_cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + logging.info(attach_result.stdout) + assert attach_result.stdout.decode('utf-8').strip() == 'attach app debug successfully.' + + @classmethod + def click_on_middle(cls): + ''' + 模拟点击屏幕中间 + ''' + get_screen_info_cmd = ['hdc', 'shell', 'hidumper', '-s', 'RenderService', '-a', 'screen'] + screen_info = subprocess.run(get_screen_info_cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + match = re.search(r'physical screen resolution: (\d+)x(\d+)', screen_info.stdout.decode('utf-8')) + assert match is not None + + middle_x = int(match.group(1)) // 2 + middle_y = int(match.group(2)) // 2 + click_cmd = ['hdc', 'shell', 'uinput', '-T', '-c', str(middle_x), str(middle_y)] + click_result = subprocess.run(click_cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + click_result_out = click_result.stdout.decode('utf-8').strip() + logging.info(click_result_out) + assert "click coordinate" in click_result_out + + @classmethod + def keep_awake(cls): + keep_awake_cmd = ['hdc', 'shell', 'power-shell', 'setmode', '602'] + keep_awake_result = subprocess.run(keep_awake_cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + keep_awake_result_out = keep_awake_result.stdout.decode('utf-8').strip() + logging.info(keep_awake_result_out) + assert "Set Mode Success!" in keep_awake_result_out \ No newline at end of file diff --git a/test/autotest/aw/cdp/cpu_profiler.py b/test/autotest/aw/cdp/cpu_profiler.py new file mode 100644 index 0000000000000000000000000000000000000000..4e0be651cf9a39f84e840937e987c71f0dfe24fb --- /dev/null +++ b/test/autotest/aw/cdp/cpu_profiler.py @@ -0,0 +1,39 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +""" +Copyright (c) 2024 Huawei Device Co., Ltd. +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +Description: Python CDP CPU Profiler. +""" + + +def enable(): + return {'method': 'Profiler.enable'} + + +def disable(): + return {'method': 'Profiler.disable'} + + +def start(): + return {'method': 'Profiler.start'} + + +def stop(): + return {'method': 'Profiler.stop'} + + +def set_sampling_interval(interval: int): + return {'method': 'Profiler.setSamplingInterval', + 'params': {'interval': interval}} \ No newline at end of file diff --git a/test/autotest/aw/cdp/debugger.py b/test/autotest/aw/cdp/debugger.py new file mode 100644 index 0000000000000000000000000000000000000000..3628d90b6504409e6f7b590b510a3c164c6cbf85 --- /dev/null +++ b/test/autotest/aw/cdp/debugger.py @@ -0,0 +1,91 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +""" +Copyright (c) 2024 Huawei Device Co., Ltd. +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +Description: Python CDP Debugger. +""" + +from dataclasses import dataclass, field +from typing import Optional, List + + +@dataclass +class BreakLocationUrl: + url: str + line_number: int + column_number: Optional[int] = 0 + + def to_json(self): + json = {'url': self.url, + 'lineNumber': self.line_number, + 'columnNumber': self.column_number} + return json + + +@dataclass +class RemoveBreakpointsUrl: + url: str = "" + + +@dataclass +class SetBreakpointsLocations: + locations: list = field(default_factory=list) + + +def enable(max_scripts_cache_size: Optional[float] = None): + command = {'method': 'Debugger.enable'} + if max_scripts_cache_size: + command['params'] = {'maxScriptsCacheSize': max_scripts_cache_size} + return command + + +def resume(): + command = {'method': 'Debugger.resume'} + return command + + +def remove_breakpoints_by_url(url: str): + command = {'method': 'Debugger.removeBreakpointsByUrl', + 'params': {'url': url}} + return command + + +def get_possible_and_set_breakpoint_by_url(locations: List[BreakLocationUrl]): + params = {'locations': []} + for location in locations: + params['locations'].append(location.to_json()) + command = {'method': 'Debugger.getPossibleAndSetBreakpointByUrl', + 'params': params} + return command + + +def step_over(): + command = {'method': 'Debugger.stepOver'} + return command + + +def step_into(): + command = {'method': 'Debugger.stepInto'} + return command + + +def step_out(): + command = {'method': 'Debugger.stepOut'} + return command + + +def disable(): + command = {'method': 'Debugger.disable'} + return command \ No newline at end of file diff --git a/test/autotest/aw/cdp/heap_profiler.py b/test/autotest/aw/cdp/heap_profiler.py new file mode 100644 index 0000000000000000000000000000000000000000..59743356be8981a598bc4fd71d86995a94190745 --- /dev/null +++ b/test/autotest/aw/cdp/heap_profiler.py @@ -0,0 +1,50 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +""" +Copyright (c) 2024 Huawei Device Co., Ltd. +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +Description: Python CDP Heap Profiler. +""" +import typing + + +def enable(): + return {'method': 'HeapProfiler.enable'} + + +def disable(): + return {'method': 'HeapProfiler.disable'} + + +def start_tracking_heap_objects(track_allocations: typing.Optional[bool] = None): + params = dict() + if track_allocations is not None: + params['trackAllocations'] = track_allocations + return {'method': 'HeapProfiler.startTrackingHeapObjects', 'params': params} + + +def stop_tracking_heap_objects(): + return {'method': 'HeapProfiler.stopTrackingHeapObjects'} + + +def start_sampling(): + return {'method': 'HeapProfiler.startSampling'} + + +def stop_sampling(): + return {'method': 'HeapProfiler.stopSampling'} + + +def take_heap_snapshot(): + return {'method': 'HeapProfiler.takeHeapSnapshot'} \ No newline at end of file diff --git a/test/autotest/aw/cdp/runtime.py b/test/autotest/aw/cdp/runtime.py new file mode 100644 index 0000000000000000000000000000000000000000..7a18cd257bef56cef5641a98b84128d8255d47e0 --- /dev/null +++ b/test/autotest/aw/cdp/runtime.py @@ -0,0 +1,61 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +""" +Copyright (c) 2024 Huawei Device Co., Ltd. +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +Description: Python CDP Runtime. +""" +from dataclasses import dataclass +from typing import Optional + + +@dataclass +class GetPropertiesParams: + object_id: str = "" + own_properties: bool = True + accessor_properties_only: bool = False + generate_preview: bool = True + + +def enable(): + command = {'method': 'Runtime.enable'} + return command + + +def run_if_waiting_for_debugger(): + command = {'method': 'Runtime.runIfWaitingForDebugger'} + return command + + +def get_properties(object_id: str, + own_properties: Optional[bool] = None, + accessor_properties_only: Optional[bool] = None, + generate_preview: Optional[bool] = None, + non_indexed_properties_only: Optional[bool] = None): + command = {'method': 'Runtime.getProperties'} + params = {'objectId': object_id} + if own_properties is not None: + params['ownProperties'] = own_properties + if accessor_properties_only is not None: + params['accessorPropertiesOnly'] = accessor_properties_only + if generate_preview is not None: + params['generatePreview'] = generate_preview + if non_indexed_properties_only is not None: + params['nonIndexedPropertiesOnly'] = non_indexed_properties_only + command['params'] = params + return command + + +def get_heap_usage(): + return {'method': 'Runtime.getHeapUsage'} \ No newline at end of file diff --git a/test/autotest/aw/fport.py b/test/autotest/aw/fport.py new file mode 100644 index 0000000000000000000000000000000000000000..7bc2dcd141c36ae5ae58f41bb61442bf56fc0a08 --- /dev/null +++ b/test/autotest/aw/fport.py @@ -0,0 +1,57 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +""" +Copyright (c) 2024 Huawei Device Co., Ltd. +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +Description: Action words of hdc fport. +""" + +import logging +import subprocess + + +class Fport(object): + @classmethod + def fport_connect_server(cls, port, pid, bundle_name): + cmd = ['hdc', 'fport', f'tcp:{port}', f'ark:{pid}@{bundle_name}'] + logging.info('fport connect server: ' + ' '.join(cmd)) + result = subprocess.run(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + logging.info(result.stdout.strip()) + assert result.stdout.decode('utf-8').strip() == 'Forwardport result:OK' + + @classmethod + def fport_debugger_server(cls, port, pid, tid=0): + if tid == 0: + cmd = ['hdc', 'fport', f'tcp:{port}', f'ark:{pid}@Debugger'] + else: + cmd = ['hdc', 'fport', f'tcp:{port}', f'ark:{pid}@{tid}@Debugger'] + logging.info('fport_debugger_server: ' + ' '.join(cmd)) + result = subprocess.run(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + logging.info(result.stdout.strip()) + assert result.stdout.decode('utf-8').strip() == 'Forwardport result:OK' + + @classmethod + def clear_fport(cls): + list_fport_cmd = ['hdc', 'fport', 'ls'] + list_fport_result = subprocess.run(list_fport_cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + logging.info(list_fport_result.stdout.strip()) + list_fport_out = list_fport_result.stdout.decode('utf-8') + if 'Empty' in list_fport_out: + return + for fport_item in [item for item in list_fport_out.split('[Forward]') if item != '\r\n']: + un_fport_command = (['hdc', 'fport', 'rm'] + [fport_item.split(' ')[1].split(' ')[0]] + + [fport_item.split(' ')[1].split(' ')[1]]) + un_fport_result = subprocess.run(un_fport_command, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + logging.info(un_fport_result.stdout.strip()) + assert 'success' in un_fport_result.stdout.decode('utf-8') diff --git a/test/autotest/aw/taskpool.py b/test/autotest/aw/taskpool.py new file mode 100644 index 0000000000000000000000000000000000000000..01c446519720ba20bb6afddb834e048b39545517 --- /dev/null +++ b/test/autotest/aw/taskpool.py @@ -0,0 +1,80 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +""" +Copyright (c) 2024 Huawei Device Co., Ltd. +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +Description: A task pool that can execute tasks asynchronously. +""" + +import asyncio +import logging +from queue import Queue +from threading import Thread + + +class TaskPool(object): + def __init__(self): + self.task_queue = Queue() + self.event_loop = None + self.task_exception = None + self._start_event_loop() + + def submit(self, coroutine, callback=None): + # add item to the task queue + self._task_add() + future = asyncio.run_coroutine_threadsafe(coro=coroutine, loop=self.event_loop) + future.add_done_callback(callback) if callback else None + # remove item from the task queue after the task is done + future.add_done_callback(self._task_done) + + def await_taskpool(self): + asyncio.run_coroutine_threadsafe(coro=self._stop_loop(), loop=self.event_loop) + + def task_join(self): + self.task_queue.join() + + def _task_add(self, item=1): + self.task_queue.put(item) + + def _task_done(self, future): + # clear the task queue and stop the task pool once an exception occurs in the task + if future.exception(): + logging.error(f'future.exception: {future.exception()}') + while not self.task_queue.empty(): + self.task_queue.get() + self.task_queue.task_done() + self.task_exception = future.exception() + return + self.task_queue.get() + self.task_queue.task_done() + + def _set_and_run_loop(self, loop): + self.event_loop = loop + asyncio.set_event_loop(loop) + loop.run_forever() + + async def _stop_loop(self, interval=1): + # wait for all tasks in the event loop is done, then we can close the loop + while True: + if self.task_queue.empty(): + self.event_loop.stop() + return + await asyncio.sleep(interval) + + def _start_event_loop(self): + loop = asyncio.new_event_loop() + event_loop_thread = Thread(target=self._set_and_run_loop, args=(loop,)) + event_loop_thread.setDaemon(True) + event_loop_thread.setName('event_loop_thread') + event_loop_thread.start() diff --git a/test/autotest/aw/types.py b/test/autotest/aw/types.py new file mode 100644 index 0000000000000000000000000000000000000000..ca3464ad48abbe92511a8a6737bcf985f53f533c --- /dev/null +++ b/test/autotest/aw/types.py @@ -0,0 +1,34 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +""" +Copyright (c) 2024 Huawei Device Co., Ltd. +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +Description: Data Transferring Classes & Types. +""" + +import asyncio +from dataclasses import dataclass +from enum import Enum + + +@dataclass(init=True) +class ThreadConnectionInfo: + instance_id: int + send_msg_queue: asyncio.Queue + received_msg_queue: asyncio.Queue + + +class ProtocolType(Enum): + send = "send", + recv = "recv" \ No newline at end of file diff --git a/test/autotest/aw/utils.py b/test/autotest/aw/utils.py new file mode 100644 index 0000000000000000000000000000000000000000..3d08f29769b35efbc9bc70667a280473329258cf --- /dev/null +++ b/test/autotest/aw/utils.py @@ -0,0 +1,159 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +""" +Copyright (c) 2024 Huawei Device Co., Ltd. +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +Description: MISC action words. +""" + +import asyncio +import logging +import os +import stat +import subprocess +import threading + +from aw.websocket import WebSocket + + +class Utils(object): + @classmethod + def message_id_generator(cls): + message_id = 1 + while True: + yield message_id + message_id += 1 + + @classmethod + def get_custom_protocols(cls): + protocols = ["removeBreakpointsByUrl", + "setMixedDebugEnabled", + "replyNativeCalling", + "getPossibleAndSetBreakpointByUrl", + "dropFrame", + "setNativeRange", + "resetSingleStepper", + "callFunctionOn", + "smartStepInto", + "callFunctionOn"] + return protocols + + @classmethod + async def communicate_with_debugger_server(cls, instance_id, to_send_queue, received_queue, command, message_id): + """ + Assembles and send the commands, then return the response. + Send message to the debugger server corresponding to the to_send_queue. + Return the response from the received_queue. + """ + command['id'] = message_id + await WebSocket.send_msg_to_debugger_server(instance_id, to_send_queue, command) + response = await WebSocket.recv_msg_of_debugger_server(instance_id, received_queue) + return response + + @classmethod + async def async_wait_timeout(cls, task, timeout=3): + try: + result = await asyncio.wait_for(task, timeout) + return result + except asyncio.TimeoutError: + logging.error('await timeout!') + + @classmethod + def hdc_target_mount(cls): + mount_cmd = ['hdc', 'target', 'mount'] + logging.info('Mount finish: ' + ' '.join(mount_cmd)) + mount_result = subprocess.run(mount_cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + logging.info(mount_result.stdout.strip()) + assert mount_result.stdout.decode('utf-8').strip() == 'Mount finish' + + @classmethod + def clear_fault_log(cls): + cmd = ['hdc', 'shell', 'rm', '/data/log/faultlog/faultlogger/*'] + logging.info(' '.join(cmd)) + result = subprocess.run(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + assert result.returncode == 0 + + @classmethod + def save_fault_log(cls, log_path): + if not os.path.exists(log_path): + os.makedirs(log_path) + + cmd = ['hdc', 'file', 'recv', '/data/log/faultlog/faultlogger/', log_path] + logging.info(' '.join(cmd)) + result = subprocess.run(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + logging.info(result.stdout.strip()) + assert result.returncode == 0 + + @classmethod + def save_hilog(cls, log_path, file_name, debug_on=False): + if not os.path.exists(log_path): + os.makedirs(log_path) + + # config the hilog + cmd = ['hdc', 'shell', 'hilog', '-r'] + logging.info(' '.join(cmd)) + result = subprocess.run(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + assert result.returncode == 0 + + if debug_on: + cmd = ['hdc', 'shell', 'hilog', '-G', '16M'] + logging.info(' '.join(cmd)) + result = subprocess.run(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + assert result.returncode == 0 + + cmd = ['hdc', 'shell', 'hilog', '-Q', 'pidoff'] + logging.info(' '.join(cmd)) + result = subprocess.run(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + assert result.returncode == 0 + + cmd = ['hdc', 'shell', 'hilog', '-Q', 'domainoff'] + logging.info(' '.join(cmd)) + result = subprocess.run(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + assert result.returncode == 0 + + cmd = ['hdc', 'shell', 'hilog', '-b', 'd'] + logging.info(' '.join(cmd)) + result = subprocess.run(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + assert result.returncode == 0 + + cmd = ['hdc', 'shell', 'setprop', 'persist.sys.hilog.debug.on', 'true'] + logging.info(' '.join(cmd)) + result = subprocess.run(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + assert result.returncode == 0 + + cmd = ['hdc', 'shell', 'hilog', '-b', 'DEBUG'] + logging.info(' '.join(cmd)) + result = subprocess.run(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + assert result.returncode == 0 + + # create a sub-process to receive the hilog + hilog_process = subprocess.Popen(['hdc', 'shell', 'hilog'], + stdout=subprocess.PIPE, stderr=subprocess.STDOUT) + file = os.fdopen(os.open(rf'{log_path}\{file_name}', + os.O_WRONLY | os.O_CREAT, + stat.S_IRUSR | stat.S_IWUSR), 'wb') + + def write(): + try: + for line in iter(hilog_process.stdout.readline, b''): + file.write(line) + file.flush() + except ValueError: + logging.info('hilog stream is closed.') + file.close() + + write_thread = threading.Thread(target=write) + write_thread.start() + + return hilog_process, write_thread diff --git a/test/autotest/aw/websocket.py b/test/autotest/aw/websocket.py new file mode 100644 index 0000000000000000000000000000000000000000..28d2bfecb9322ecbb5153253f7c45649b3d6fa6b --- /dev/null +++ b/test/autotest/aw/websocket.py @@ -0,0 +1,162 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +""" +Copyright (c) 2024 Huawei Device Co., Ltd. +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +Description: Responsible for websocket communication. +""" + +import asyncio +import json +import logging + +import websockets.protocol +from websockets import connect, ConnectionClosed + +from aw.fport import Fport + + +class WebSocket(object): + def __init__(self, connect_server_port, debugger_server_port): + self.connect_server_port = connect_server_port + self.debugger_server_port = debugger_server_port + self.debugger_server_connection_threshold = 3 + + self.to_send_msg_queue_for_connect_server = None + self.received_msg_queue_for_connect_server = None + + self.to_send_msg_queues = {} # key: instance_id, value: to_send_msg_queue + self.received_msg_queues = {} # key: instance_id, value: received_msg_queue + self.debugger_server_instance = None + + @staticmethod + async def recv_msg_of_debugger_server(instance_id, queue): + message = await queue.get() + queue.task_done() + logging.info(f'[<==] Instance {instance_id} receive message: {message}') + return message + + @staticmethod + async def send_msg_to_debugger_server(instance_id, queue, message): + await queue.put(message) + logging.info(f'[==>] Instance {instance_id} send message: {message}') + return True + + @staticmethod + async def _sender(client, send_queue): + assert client.state == websockets.protocol.OPEN, logging.error(f'Client state of _sender is: {client.state}') + while True: + send_message = await send_queue.get() + send_queue.task_done() + if send_message == 'close': + await client.close(reason='close') + return + await client.send(json.dumps(send_message)) + + @staticmethod + async def _receiver(client, received_queue): + assert client.state == websockets.protocol.OPEN, logging.error(f'Client state of _receiver is: {client.state}') + while True: + try: + response = await client.recv() + await received_queue.put(response) + except ConnectionClosed: + logging.info('Debugger server connection closed') + return + + async def get_instance(self): + instance_id = await self.debugger_server_instance.get() + self.debugger_server_instance.task_done() + return instance_id + + async def recv_msg_of_connect_server(self): + message = await self.received_msg_queue_for_connect_server.get() + self.received_msg_queue_for_connect_server.task_done() + return message + + async def send_msg_to_connect_server(self, message): + await self.to_send_msg_queue_for_connect_server.put(message) + logging.info(f'[==>] Connect server send message: {message}') + return True + + async def main_task(self, taskpool, websocket, procedure, pid): + # the async queue must be initialized in task + self.to_send_msg_queue_for_connect_server = asyncio.Queue() + self.received_msg_queue_for_connect_server = asyncio.Queue() + self.debugger_server_instance = asyncio.Queue(maxsize=1) + + connect_server_client = await self._connect_connect_server() + taskpool.submit(self._sender(connect_server_client, self.to_send_msg_queue_for_connect_server)) + taskpool.submit(self._receiver_of_connect_server(connect_server_client, + self.received_msg_queue_for_connect_server, + taskpool, pid)) + taskpool.submit(procedure(websocket)) + + def _connect_connect_server(self): + client = connect(f'ws://localhost:{self.connect_server_port}', + open_timeout=10, + ping_interval=None) + return client + + def _connect_debugger_server(self): + client = connect(f'ws://localhost:{self.debugger_server_port}', + open_timeout=6, + ping_interval=None) + return client + + async def _receiver_of_connect_server(self, client, receive_queue, taskpool, pid): + assert client.state == websockets.protocol.OPEN, \ + logging.error(f'Client state of _receiver_of_connect_server is: {client.state}') + num_debugger_server_client = 0 + while True: + try: + response = await client.recv() + await receive_queue.put(response) + logging.info(f'[<==] Connect server receive message: {response}') + response = json.loads(response) + + # The debugger server client is only responsible for adding and removing instances + if (response['type'] == 'addInstance' and + num_debugger_server_client < self.debugger_server_connection_threshold): + instance_id = response['instanceId'] + + Fport.fport_debugger_server(self.debugger_server_port, pid, instance_id) + debugger_server_client = await self._connect_debugger_server() + logging.info(f'InstanceId: {instance_id}, port: {self.debugger_server_port}, ' + f'debugger server connected') + self.debugger_server_port += 1 + + to_send_msg_queue = asyncio.Queue() + received_msg_queue = asyncio.Queue() + self.to_send_msg_queues[instance_id] = to_send_msg_queue + self.received_msg_queues[instance_id] = received_msg_queue + taskpool.submit(coroutine=self._sender(debugger_server_client, to_send_msg_queue)) + taskpool.submit(coroutine=self._receiver(debugger_server_client, received_msg_queue)) + + await self._store_instance(instance_id) + num_debugger_server_client += 1 + + elif response['type'] == 'destroyInstance': + instance_id = response['instanceId'] + to_send_msg_queue = self.to_send_msg_queues[instance_id] + await self.send_msg_to_debugger_server(instance_id, to_send_msg_queue, 'close') + num_debugger_server_client -= 1 + + except ConnectionClosed: + logging.info('Connect server connection closed') + return + + async def _store_instance(self, instance_id): + await self.debugger_server_instance.put(instance_id) + return True diff --git a/test/autotest/pytest.ini b/test/autotest/pytest.ini new file mode 100644 index 0000000000000000000000000000000000000000..6b882901a00109e30b8cc6241098ad146c17a312 --- /dev/null +++ b/test/autotest/pytest.ini @@ -0,0 +1,16 @@ +[pytest] + +log_cli = true + +log_level = info +log_format = [+] %(asctime)s - %(filename)s - [line:%(lineno)d] - %(levelname)s: %(message)s +log_date_format = %Y-%m-%d %H:%M:%S + +markers = + debug: marks tests as debug + cpu_profiler: marks tests as cpu profiler + heap_profiler: marks tests as heap profiler + +testpaths = ./scenario_test + +addopts = -vv --html ./report/report.html --self-contained-html diff --git a/test/autotest/requirements.txt b/test/autotest/requirements.txt new file mode 100644 index 0000000000000000000000000000000000000000..dd72420c7ca5d5b676fc586ac69eaa5b69d9a083 --- /dev/null +++ b/test/autotest/requirements.txt @@ -0,0 +1,6 @@ +pytest==8.3.1 +pytest-timeout==2.3.1 +pytest-metadata==3.1.1 +pytest-html==4.1.1 +pluggy==1.5.0 +websockets==12.0 diff --git a/test/autotest/resource/archive.json b/test/autotest/resource/archive.json new file mode 100644 index 0000000000000000000000000000000000000000..5d18fb46c2a8a4e0c2c54988d4a8e38e39df8f70 --- /dev/null +++ b/test/autotest/resource/archive.json @@ -0,0 +1,17 @@ +[ + { + "application directory": "MultiWorker01", + "hap name": "MultiWorker01.hap", + "bundle name": "com.example.multiWorker01" + }, + { + "application directory": "MultiWorker02", + "hap name": "MultiWorker02.hap", + "bundle name": "com.example.multiWorker02" + }, + { + "application directory": "TaskPool01", + "hap name": "TaskPool01.hap", + "bundle name": "com.example.taskPool01" + } +] \ No newline at end of file diff --git a/test/autotest/run.py b/test/autotest/run.py new file mode 100644 index 0000000000000000000000000000000000000000..b45b2c88b4f5ca6cc5852b8aadc090a48670d5d9 --- /dev/null +++ b/test/autotest/run.py @@ -0,0 +1,57 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +""" +Copyright (c) 2024 Huawei Device Co., Ltd. +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +Description: Run all test cases. +""" + +import logging +import os +import subprocess +import sys + +import pytest + +sys.path.append(os.path.join(os.path.dirname(__file__), '..')) + + +def check_python_version(): + required_version = (3, 8, 0) + current_version = sys.version_info + + if current_version >= required_version: + logging.info(f"Python version meets requirements: " + f"{current_version.major}.{current_version.minor}.{current_version.micro}") + else: + logging.error(f"Python version too low: " + f"{current_version.major}.{current_version.minor}.{current_version.micro}, " + f"needs to be at least 3.8.0") + sys.exit(1) + + +def install_requirements(requirements_file=r'.\requirements.txt'): + try: + subprocess.check_call([sys.executable, '-m', 'pip', 'install', '-r', requirements_file], timeout=10) + logging.info(f'Successfully installed dependencies from {requirements_file}') + except subprocess.CalledProcessError as e: + logging.error(f'Error occurred while installing dependencies: {e}') + sys.exit(1) + + +if __name__ == '__main__': + check_python_version() + install_requirements() + + pytest.main() diff --git a/test/autotest/scenario_test/conftest.py b/test/autotest/scenario_test/conftest.py new file mode 100644 index 0000000000000000000000000000000000000000..98822b5ffeaa5ca94111ca29ee3c6df5d94c9f3f --- /dev/null +++ b/test/autotest/scenario_test/conftest.py @@ -0,0 +1,145 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +""" +Copyright (c) 2024 Huawei Device Co., Ltd. +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +Description: Fixtures of pytest. +""" + +import logging +import os + +import pytest + +from aw import Application, Fport, WebSocket, TaskPool + + +@pytest.fixture(scope='class') +def test_suite_worker_01(): + logging.info('running worker_01 in default mode') + config = { + 'start_mode': None, + 'connect_server_port': 15678, + 'debugger_server_port': 15679, + 'bundle_name': 'com.example.multiWorker01', + 'hap_name': 'MultiWorker01.hap', + 'hap_path': rf'{os.path.dirname(__file__)}\..\resource\MultiWorker01.hap', + 'file_path': { + 'entry_ability': 'entry|entry|1.0.0|src/main/ets/entryability/EntryAbility.ts', + 'index': 'entry|entry|1.0.0|src/main/ets/pages/Index.ts', + 'worker': 'entry|entry|1.0.0|src/main/ets/workers/Worker.ts' + } + } + launch_hap(config) + return config + + +@pytest.fixture(scope='class') +def test_suite_worker_01_debug(): + logging.info('running worker_01 in debug mode') + config = { + 'start_mode': '-D', + 'connect_server_port': 15678, + 'debugger_server_port': 15679, + 'bundle_name': 'com.example.multiWorker01', + 'hap_name': 'MultiWorker01.hap', + 'hap_path': rf'{os.path.dirname(__file__)}\..\resource\MultiWorker01.hap', + 'file_path': { + 'entry_ability': 'entry|entry|1.0.0|src/main/ets/entryability/EntryAbility.ts', + 'index': 'entry|entry|1.0.0|src/main/ets/pages/Index.ts', + 'worker': 'entry|entry|1.0.0|src/main/ets/workers/Worker.ts' + } + } + launch_hap(config) + return config + + +@pytest.fixture(scope='class') +def test_suite_worker_02(): + logging.info('running worker_02 in default mode') + config = { + 'start_mode': None, + 'connect_server_port': 15680, + 'debugger_server_port': 15681, + 'bundle_name': 'com.example.multiWorker02', + 'hap_name': 'MultiWorker02.hap', + 'hap_path': rf'{os.path.dirname(__file__)}\..\resource\MultiWorker02.hap' + } + launch_hap(config) + return config + + +@pytest.fixture(scope='class') +def test_suite_worker_02_profile(): + logging.info('running worker_02 in profile mode') + config = { + 'start_mode': '-p profile jsperf', + 'connect_server_port': 15680, + 'debugger_server_port': 15681, + 'bundle_name': 'com.example.multiWorker02', + 'hap_name': 'MultiWorker02.hap', + 'hap_path': rf'{os.path.dirname(__file__)}\..\resource\MultiWorker02.hap' + } + launch_hap(config) + return config + + +@pytest.fixture(scope='class') +def test_suite_taskpool_01(): + logging.info('running taskpool_01 in default mode') + config = { + 'start_mode': None, + 'connect_server_port': 15682, + 'debugger_server_port': 15683, + 'bundle_name': 'com.example.taskPool01', + 'hap_name': 'TaskPool01.hap', + 'hap_path': rf'{os.path.dirname(__file__)}\..\resource\TaskPool01.hap', + 'file_path': { + 'entry_ability': 'entry|entry|1.0.0|src/main/ets/entryability/EntryAbility.ts', + 'index': 'entry|entry|1.0.0|src/main/ets/pages/Index.ts', + } + } + launch_hap(config) + return config + + +@pytest.fixture(scope='class') +def test_suite_taskpool_01_debug(): + logging.info('running taskpool_01 in debug mode') + config = { + 'start_mode': '-D', + 'connect_server_port': 15682, + 'debugger_server_port': 15683, + 'bundle_name': 'com.example.taskPool01', + 'hap_name': 'TaskPool01.hap', + 'hap_path': rf'{os.path.dirname(__file__)}\..\resource\TaskPool01.hap', + 'file_path': { + 'entry_ability': 'entry|entry|1.0.0|src/main/ets/entryability/EntryAbility.ts', + 'index': 'entry|entry|1.0.0|src/main/ets/pages/Index.ts', + } + } + launch_hap(config) + return config + + +def launch_hap(config): + pid = Application.launch_application(config['bundle_name'], config['hap_path'], start_mode=config['start_mode']) + assert pid != 0, logging.error(f'Pid of {config["hap_name"]} is 0!') + config['pid'] = pid + + Fport.clear_fport() + Fport.fport_connect_server(config['connect_server_port'], config['pid'], config['bundle_name']) + + config['websocket'] = WebSocket(config['connect_server_port'], config['debugger_server_port']) + config['taskpool'] = TaskPool() \ No newline at end of file diff --git a/test/autotest/scenario_test/test_cpu_profiler_01.py b/test/autotest/scenario_test/test_cpu_profiler_01.py new file mode 100644 index 0000000000000000000000000000000000000000..0161f3e8a3ec0811f540724b312617d2fd1fb17a --- /dev/null +++ b/test/autotest/scenario_test/test_cpu_profiler_01.py @@ -0,0 +1,237 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +""" +Copyright (c) 2024 Huawei Device Co., Ltd. +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +Description: Scenario test case. +""" + +import json +import logging +import os +import time + +import pytest + +from aw import Utils +from aw import Application +from aw import communicate_with_debugger_server +from aw import runtime, debugger, cpu_profiler + + +@pytest.mark.cpu_profiler +@pytest.mark.timeout(40) +class TestCpuProfiler01: + """ + 测试用例:多实例 CPU 调优 Time 录制 + 测试步骤: + 1. 连接 connect server 和主线程 debugger server + 2. 连接 worker 线程 debugger server + 3. 所有线程使能 Runtime(Runtime.enable) + 4. 所有线程设置采样间隔(Profiler.setSamplingInterval) + 5. 所有线程启动 CPU 调试(Profiler.start) + 6. 所有线程去使能 Debugger(Debugger.disable) + 7. 等待 10 秒后关闭 CPU 调优,获取调优数据(Profiler.stop) + 8. 销毁 worker 线程,对应的 debugger server 连接断开 + 9. 关闭主线程 debugger server 和 connect server 连接 + """ + + def setup_method(self): + logging.info('Start running TestCpuProfiler01: setup') + + self.log_path = rf'{os.path.dirname(__file__)}\..\log' + self.hilog_file_name = 'test_cpu_profiler_01.hilog.txt' + self.id_generator = Utils.message_id_generator() + + # receive the hilog before the test start + Utils.clear_fault_log() + self.hilog_process, self.write_thread = Utils.save_hilog(log_path=self.log_path, + file_name=self.hilog_file_name, + debug_on=True) + + def teardown_method(self): + Application.uninstall(self.config['bundle_name']) + + # terminate the hilog receive process after the test done + time.sleep(3) + self.hilog_process.stdout.close() + self.hilog_process.terminate() + self.hilog_process.wait() + self.write_thread.join() + + Utils.save_fault_log(log_path=self.log_path) + logging.info('TestCpuProfiler01 done') + + def test(self, test_suite_worker_02): + logging.info('Start running TestCpuProfiler01: test') + self.config = test_suite_worker_02 + websocket = self.config['websocket'] + taskpool = self.config['taskpool'] + pid = self.config['pid'] + + taskpool.submit(websocket.main_task(taskpool, websocket, self.procedure, pid)) + taskpool.await_taskpool() + taskpool.task_join() + if taskpool.task_exception: + raise taskpool.task_exception + + async def procedure(self, websocket): + ################################################################################################################ + # main thread: connect the debugger server + ################################################################################################################ + send_msg = {"type": "connected"} + await websocket.send_msg_to_connect_server(send_msg) + response = await websocket.recv_msg_of_connect_server() + response = json.loads(response) + assert response['type'] == 'addInstance' + assert response['instanceId'] == 0, logging.error('instance id of the main thread not equal to 0') + assert response['tid'] == self.config['pid'] + main_thread_instance_id = await websocket.get_instance() + main_thread_to_send_queue = websocket.to_send_msg_queues[main_thread_instance_id] + main_thread_received_queue = websocket.received_msg_queues[main_thread_instance_id] + logging.info(f'Connect to the debugger server of instance: {main_thread_instance_id}') + ################################################################################################################ + # worker thread: connect the debugger server + ################################################################################################################ + workers_num = 2 + worker_instances_id = [] + worker_thread_to_send_queues = [] + worker_thread_received_queues = [] + for i in range(workers_num): + response = await websocket.recv_msg_of_connect_server() + response = json.loads(response) + assert response['type'] == 'addInstance' + assert response['instanceId'] != 0 + assert response['tid'] != self.config['pid'] + assert 'workerThread_' in response['name'] + worker_instance_id = await websocket.get_instance() + worker_instances_id.append(worker_instance_id) + worker_thread_to_send_queues.append(websocket.to_send_msg_queues[worker_instance_id]) + worker_thread_received_queues.append(websocket.received_msg_queues[worker_instance_id]) + logging.info(f'Connect to the debugger server of instance: {worker_instance_id}') + ################################################################################################################ + # main thread: Runtime.enable + ################################################################################################################ + message_id = next(self.id_generator) + response = await communicate_with_debugger_server(main_thread_instance_id, + main_thread_to_send_queue, + main_thread_received_queue, + runtime.enable(), message_id) + assert json.loads(response) == {"id": message_id, "result": {"protocols": []}} + ################################################################################################################ + # worker thread: Runtime.enable + ################################################################################################################ + for i in range(workers_num): + message_id = next(self.id_generator) + response = await communicate_with_debugger_server(worker_instances_id[i], + worker_thread_to_send_queues[i], + worker_thread_received_queues[i], + runtime.enable(), message_id) + assert json.loads(response) == {"id": message_id, "result": {"protocols": []}} + ################################################################################################################ + # main thread: Profiler.setSamplingInterval + ################################################################################################################ + message_id = next(self.id_generator) + response = await communicate_with_debugger_server(main_thread_instance_id, + main_thread_to_send_queue, + main_thread_received_queue, + cpu_profiler.set_sampling_interval(500), message_id) + assert json.loads(response) == {"id": message_id, "result": {}} + ################################################################################################################ + # worker thread: Profiler.setSamplingInterval + ################################################################################################################ + for i in range(workers_num): + message_id = next(self.id_generator) + response = await communicate_with_debugger_server(worker_instances_id[i], + worker_thread_to_send_queues[i], + worker_thread_received_queues[i], + cpu_profiler.set_sampling_interval(500), message_id) + assert json.loads(response) == {"id": message_id, "result": {}} + ################################################################################################################ + # main thread: Profiler.start + ################################################################################################################ + message_id = next(self.id_generator) + response = await communicate_with_debugger_server(main_thread_instance_id, + main_thread_to_send_queue, + main_thread_received_queue, + cpu_profiler.start(), message_id) + assert json.loads(response) == {"id": message_id, "result": {}} + ################################################################################################################ + # worker thread: Profiler.start + ################################################################################################################ + for i in range(workers_num): + message_id = next(self.id_generator) + response = await communicate_with_debugger_server(worker_instances_id[i], + worker_thread_to_send_queues[i], + worker_thread_received_queues[i], + cpu_profiler.start(), message_id) + assert json.loads(response) == {"id": message_id, "result": {}} + ################################################################################################################ + # main thread: Debugger.disable + ################################################################################################################ + message_id = next(self.id_generator) + response = await communicate_with_debugger_server(main_thread_instance_id, + main_thread_to_send_queue, + main_thread_received_queue, + debugger.disable(), message_id) + assert json.loads(response) == {"id": message_id, "result": {}} + ################################################################################################################ + # worker thread: Debugger.disable + ################################################################################################################ + for i in range(workers_num): + message_id = next(self.id_generator) + response = await communicate_with_debugger_server(worker_instances_id[i], + worker_thread_to_send_queues[i], + worker_thread_received_queues[i], + debugger.disable(), message_id) + assert json.loads(response) == {"id": message_id, "result": {}} + ################################################################################################################ + # all thread: sleep 10 seconds + ################################################################################################################ + time.sleep(10) + ################################################################################################################ + # main thread: Profiler.stop + ################################################################################################################ + message_id = next(self.id_generator) + response = await communicate_with_debugger_server(main_thread_instance_id, + main_thread_to_send_queue, + main_thread_received_queue, + cpu_profiler.stop(), message_id) + response = json.loads(response) + assert response['id'] == message_id + assert all(i >= 0 for i in response['result']['profile']['timeDeltas']) + ################################################################################################################ + # worker thread: Profiler.stop + ################################################################################################################ + for i in range(workers_num): + message_id = next(self.id_generator) + response = await communicate_with_debugger_server(worker_instances_id[i], + worker_thread_to_send_queues[i], + worker_thread_received_queues[i], + cpu_profiler.stop(), message_id) + response = json.loads(response) + assert response['id'] == message_id + assert all(i >= 0 for i in response['result']['profile']['timeDeltas']) + ################################################################################################################ + # worker thread: destroy instance + ################################################################################################################ + for i in range(workers_num): + await websocket.send_msg_to_debugger_server(worker_instances_id[i], + worker_thread_to_send_queues[i], 'close') + ################################################################################################################ + # close the websocket connections + ################################################################################################################ + await websocket.send_msg_to_debugger_server(main_thread_instance_id, main_thread_to_send_queue, 'close') + await websocket.send_msg_to_connect_server('close') + ################################################################################################################ \ No newline at end of file diff --git a/test/autotest/scenario_test/test_cpu_profiler_02.py b/test/autotest/scenario_test/test_cpu_profiler_02.py new file mode 100644 index 0000000000000000000000000000000000000000..48b67c284c5726fc158eb66afa72e44c99066b6a --- /dev/null +++ b/test/autotest/scenario_test/test_cpu_profiler_02.py @@ -0,0 +1,203 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +""" +Copyright (c) 2024 Huawei Device Co., Ltd. +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +Description: Scenario test case. +""" + +import json +import logging +import os +import time + +import pytest + +from aw import Utils +from aw import Application +from aw import communicate_with_debugger_server +from aw import runtime, debugger, cpu_profiler + + +@pytest.mark.cpu_profiler +@pytest.mark.timeout(40) +class TestCpuProfiler02: + """ + 测试用例:多实例 CPU 调优 Launch 录制 + 测试步骤: + 1. -p 模式启动应用 + 2. 连接 connect server 和主线程 debugger server + 3. 连接 worker 线程 debugger server + 4. worker 线程使能 Runtime(Runtime.enable) + 5. worker 线程设置采样间隔(Profiler.setSamplingInterval) + 6. worker 线程启动 CPU 调试(Profiler.start) + 7. worker 线程去使能 Debugger(Debugger.disable) + 8. 等待 10 秒后关闭 worker 线程 CPU 调优,获取 worker 线程调优数据(Profiler.stop) + 9. 销毁 worker 线程,对应的 debugger server 连接断开 + 10. 关闭主线程 CPU 调优,获取主线程调优数据(Profiler.stop) + 11. 关闭主线程 debugger server 和 connect server 连接 + """ + + def setup_method(self): + logging.info('Start running TestCpuProfiler02: setup') + + self.log_path = rf'{os.path.dirname(__file__)}\..\log' + self.hilog_file_name = 'test_cpu_profiler_02.hilog.txt' + self.id_generator = Utils.message_id_generator() + + # receive the hilog before the test start + Utils.clear_fault_log() + self.hilog_process, self.write_thread = Utils.save_hilog(log_path=self.log_path, + file_name=self.hilog_file_name, + debug_on=True) + + def teardown_method(self): + Application.uninstall(self.config['bundle_name']) + + # terminate the hilog receive process after the test done + time.sleep(3) + self.hilog_process.stdout.close() + self.hilog_process.terminate() + self.hilog_process.wait() + self.write_thread.join() + + Utils.save_fault_log(log_path=self.log_path) + logging.info('TestCpuProfiler02 done') + + def test(self, test_suite_worker_02_profile): + logging.info('Start running TestCpuProfiler02: test') + self.config = test_suite_worker_02_profile + websocket = self.config['websocket'] + taskpool = self.config['taskpool'] + pid = self.config['pid'] + + taskpool.submit(websocket.main_task(taskpool, websocket, self.procedure, pid)) + taskpool.await_taskpool() + taskpool.task_join() + if taskpool.task_exception: + raise taskpool.task_exception + + async def procedure(self, websocket): + ################################################################################################################ + # main thread: connect the debugger server + ################################################################################################################ + send_msg = {"type": "connected"} + await websocket.send_msg_to_connect_server(send_msg) + response = await websocket.recv_msg_of_connect_server() + response = json.loads(response) + assert response['type'] == 'addInstance' + assert response['instanceId'] == 0, logging.error('instance id of the main thread not equal to 0') + assert response['tid'] == self.config['pid'] + main_thread_instance_id = await websocket.get_instance() + main_thread_to_send_queue = websocket.to_send_msg_queues[main_thread_instance_id] + main_thread_received_queue = websocket.received_msg_queues[main_thread_instance_id] + logging.info(f'Connect to the debugger server of instance: {main_thread_instance_id}') + ################################################################################################################ + # worker thread: connect the debugger server + ################################################################################################################ + workers_num = 2 + worker_instances_id = [] + worker_thread_to_send_queues = [] + worker_thread_received_queues = [] + for i in range(workers_num): + response = await websocket.recv_msg_of_connect_server() + response = json.loads(response) + assert response['type'] == 'addInstance' + assert response['instanceId'] != 0 + assert response['tid'] != self.config['pid'] + assert 'workerThread_' in response['name'] + worker_instance_id = await websocket.get_instance() + worker_instances_id.append(worker_instance_id) + worker_thread_to_send_queues.append(websocket.to_send_msg_queues[worker_instance_id]) + worker_thread_received_queues.append(websocket.received_msg_queues[worker_instance_id]) + logging.info(f'Connect to the debugger server of instance: {worker_instance_id}') + ################################################################################################################ + # worker thread: Runtime.enable + ################################################################################################################ + for i in range(workers_num): + message_id = next(self.id_generator) + response = await communicate_with_debugger_server(worker_instances_id[i], + worker_thread_to_send_queues[i], + worker_thread_received_queues[i], + runtime.enable(), message_id) + assert json.loads(response) == {"id": message_id, "result": {"protocols": []}} + ################################################################################################################ + # worker thread: Profiler.setSamplingInterval + ################################################################################################################ + for i in range(workers_num): + message_id = next(self.id_generator) + response = await communicate_with_debugger_server(worker_instances_id[i], + worker_thread_to_send_queues[i], + worker_thread_received_queues[i], + cpu_profiler.set_sampling_interval(500), message_id) + assert json.loads(response) == {"id": message_id, "result": {}} + ################################################################################################################ + # worker thread: Profiler.start + ################################################################################################################ + for i in range(workers_num): + message_id = next(self.id_generator) + response = await communicate_with_debugger_server(worker_instances_id[i], + worker_thread_to_send_queues[i], + worker_thread_received_queues[i], + cpu_profiler.start(), message_id) + assert json.loads(response) == {"id": message_id, "result": {}} + ################################################################################################################ + # worker thread: Debugger.disable + ################################################################################################################ + for i in range(workers_num): + message_id = next(self.id_generator) + response = await communicate_with_debugger_server(worker_instances_id[i], + worker_thread_to_send_queues[i], + worker_thread_received_queues[i], + debugger.disable(), message_id) + assert json.loads(response) == {"id": message_id, "result": {}} + ################################################################################################################ + # all thread: sleep 10 seconds + ################################################################################################################ + time.sleep(10) + ################################################################################################################ + # worker thread: Profiler.stop + ################################################################################################################ + for i in range(workers_num): + message_id = next(self.id_generator) + response = await communicate_with_debugger_server(worker_instances_id[i], + worker_thread_to_send_queues[i], + worker_thread_received_queues[i], + cpu_profiler.stop(), message_id) + response = json.loads(response) + assert response['id'] == message_id + assert all(i >= 0 for i in response['result']['profile']['timeDeltas']) + ################################################################################################################ + # worker thread: destroy instance + ################################################################################################################ + for i in range(workers_num): + await websocket.send_msg_to_debugger_server(worker_instances_id[i], + worker_thread_to_send_queues[i], 'close') + ################################################################################################################ + # main thread: Profiler.stop + ################################################################################################################ + message_id = next(self.id_generator) + response = await communicate_with_debugger_server(main_thread_instance_id, + main_thread_to_send_queue, + main_thread_received_queue, + cpu_profiler.stop(), message_id) + response = json.loads(response) + assert response['id'] == message_id + assert all(i >= 0 for i in response['result']['profile']['timeDeltas']) + ################################################################################################################ + # close the websocket connections + ################################################################################################################ + await websocket.send_msg_to_debugger_server(main_thread_instance_id, main_thread_to_send_queue, 'close') + await websocket.send_msg_to_connect_server('close') + ################################################################################################################ \ No newline at end of file diff --git a/test/autotest/scenario_test/test_debug_01.py b/test/autotest/scenario_test/test_debug_01.py new file mode 100644 index 0000000000000000000000000000000000000000..c3eadbe39be47a75fb7d1fc20b02b5299a815f9d --- /dev/null +++ b/test/autotest/scenario_test/test_debug_01.py @@ -0,0 +1,407 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +""" +Copyright (c) 2024 Huawei Device Co., Ltd. +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +Description: Scenario test case. +""" + +import logging +import os +import time + +import pytest + +from aw import Application +from aw import Utils +from aw import debugger, runtime +from aw.api import debugger_api, runtime_api + + +@pytest.mark.debug +@pytest.mark.timeout(30) +class TestDebug01: + """ + 测试用例:多实例 debug 调试 + 测试步骤: + 1. 连接 connect server 和主线程 debugger server + 2. 主线程使能 Runtime 和 Debugger + 3. 主线程 Index.ts 文件设置断点(Debugger.getPossibleAndSetBreakpointByUrl) + 4. 主线程 stepOut,暂停在下一断点(Debugger.stepOut) + 5. 创建第一个子线程,连接子线程 debugger server + 6. 主线程 resume,暂停在下一断点(Debugger.resume) + 7. 创建另一个子线程,连接子线程 debugger server + 8. 所有子线程使能 Runtime 和 Debugger + 9. 所有子线程 Worker.ts 文件设置断点(Debugger.getPossibleAndSetBreakpointByUrl) + 10. 触发点击事件,主线程命中断点 + 11. 销毁其中一个子线程 + 12. 主线程 stepInto,暂停在下一行(Debugger.stepInto) + 13. 主线程 getProperties,返回给定对象的属性(Runtime.getProperties) + 14. 主线程 resume,暂停在下一断点(Debugger.resume) + 15. 重新创建一个子线程,使能并设置断点 + 16. 主线程 resume,发送消息给子线程,主线程暂停在下一断点(Debugger.resume) + 17. 子线程命中断点后 getProperties(Runtime.getProperties) + 18. 子线程 stepOut 发消息给主线程(Debugger.stepOut) + 19. 主线程 stepOver,发送消息给另一子线程,主线程暂停在下一行(Debugger.stepOver) + 20. 子线程命中断点后 resume,发消息给主线程(Debugger.resume) + 21. 销毁所有子线程,对应的 debugger server 连接断开 + 22. 关闭主线程 debugger server 和 connect server 连接 + """ + + def setup_method(self): + logging.info('Start running TestDebug01: setup') + + self.log_path = rf'{os.path.dirname(__file__)}\..\log' + self.hilog_file_name = 'test_debug_01.hilog.txt' + self.id_generator = Utils.message_id_generator() + + # receive the hilog before the test start + Utils.clear_fault_log() + self.hilog_process, self.write_thread = Utils.save_hilog(log_path=self.log_path, + file_name=self.hilog_file_name, + debug_on=True) + self.debugger_impl = debugger_api.DebuggerImpl(self.id_generator) + self.runtime_impl = runtime_api.RuntimeImpl(self.id_generator) + + def teardown_method(self): + Application.uninstall(self.config['bundle_name']) + + # terminate the hilog receive process after the test done + time.sleep(3) + self.hilog_process.stdout.close() + self.hilog_process.terminate() + self.hilog_process.wait() + self.write_thread.join() + + Utils.save_fault_log(log_path=self.log_path) + logging.info('TestDebug01 done') + + def test(self, test_suite_worker_01_debug): + logging.info('Start running TestDebug01: test') + self.config = test_suite_worker_01_debug + websocket = self.config['websocket'] + taskpool = self.config['taskpool'] + pid = self.config['pid'] + + taskpool.submit(websocket.main_task(taskpool, websocket, self.procedure, pid)) + taskpool.await_taskpool() + taskpool.task_join() + if taskpool.task_exception: + raise taskpool.task_exception + + async def procedure(self, websocket): + ################################################################################################################ + # main thread: connect the debugger server + ################################################################################################################ + main_thread = await self.debugger_impl.connect_to_debugger_server(websocket, self.config['pid'], True) + logging.info(f'Connect to the debugger server of instance: {main_thread.instance_id}') + ################################################################################################################ + # main thread: Runtime.enable + ################################################################################################################ + await self.runtime_impl.send("Runtime.enable", main_thread) + ################################################################################################################ + # main thread: Debugger.enable + ################################################################################################################ + await self.debugger_impl.send("Debugger.enable", main_thread, websocket) + ################################################################################################################ + # main thread: Runtime.runIfWaitingForDebugger + ################################################################################################################ + await self.runtime_impl.send("Runtime.runIfWaitingForDebugger", main_thread) + ################################################################################################################ + # main thread: Debugger.scriptParsed + ################################################################################################################ + response = await self.debugger_impl.recv("Debugger.scriptParsed", main_thread, websocket) + assert response['params']['url'] == self.config['file_path']['entry_ability'] + assert response['params']['endLine'] == 0 + ################################################################################################################ + # main thread: Debugger.paused + ################################################################################################################ + response = await self.debugger_impl.recv("Debugger.paused", main_thread, websocket) + assert response['params']['callFrames'][0]['url'] == self.config['file_path']['entry_ability'] + assert response['params']['reason'] == 'Break on start' + ################################################################################################################ + # main thread: Debugger.resume + ################################################################################################################ + await self.debugger_impl.send("Debugger.resume", main_thread, websocket) + ################################################################################################################ + # main thread: Debugger.scriptParsed + ################################################################################################################ + response = await self.debugger_impl.recv("Debugger.scriptParsed", main_thread, websocket) + assert response['params']['url'] == self.config['file_path']['index'] + assert response['params']['endLine'] == 0 + ################################################################################################################ + # main thread: Debugger.paused + ################################################################################################################ + response = await self.debugger_impl.recv("Debugger.paused", main_thread, websocket) + assert response['params']['callFrames'][0]['url'] == self.config['file_path']['index'] + assert response['params']['reason'] == 'Break on start' + ################################################################################################################ + # main thread: Debugger.removeBreakpointsByUrl + ################################################################################################################ + params = debugger.RemoveBreakpointsUrl(self.config['file_path']['index']) + await self.debugger_impl.send("Debugger.removeBreakpointsByUrl", main_thread, websocket, params) + ################################################################################################################ + # main thread: Debugger.getPossibleAndSetBreakpointByUrl + ################################################################################################################ + locations = [debugger.BreakLocationUrl(url=self.config['file_path']['index'], line_number=12), + debugger.BreakLocationUrl(url=self.config['file_path']['index'], line_number=53), + debugger.BreakLocationUrl(url=self.config['file_path']['index'], line_number=57)] + params = debugger.SetBreakpointsLocations(locations) + response = await self.debugger_impl.send("Debugger.getPossibleAndSetBreakpointsByUrl", + main_thread, websocket, params) + assert response['result']['locations'][0]['id'] == 'id:12:0:' + self.config['file_path']['index'] + assert response['result']['locations'][1]['id'] == 'id:53:0:' + self.config['file_path']['index'] + assert response['result']['locations'][2]['id'] == 'id:57:0:' + self.config['file_path']['index'] + ################################################################################################################ + # main thread: Debugger.resume + ################################################################################################################ + await self.debugger_impl.send("Debugger.resume", main_thread, websocket) + ################################################################################################################ + # main thread: Debugger.paused, hit breakpoint + ################################################################################################################ + response = await self.debugger_impl.recv("Debugger.paused", main_thread, websocket) + assert response['params']['callFrames'][0]['url'] == self.config['file_path']['index'] + assert response['params']['hitBreakpoints'] == ['id:12:4:' + self.config['file_path']['index']] + ################################################################################################################ + # main thread: Debugger.stepOut + ################################################################################################################ + await self.debugger_impl.send("Debugger.stepOut", main_thread, websocket) + response = await self.debugger_impl.recv("Debugger.paused", main_thread, websocket) + assert response['params']['callFrames'][0]['url'] == self.config['file_path']['index'] + assert response['params']['hitBreakpoints'] == ['id:12:4:' + self.config['file_path']['index']] + ################################################################################################################ + # worker thread: connect the debugger server + ################################################################################################################ + worker_thread_1 = await self.debugger_impl.connect_to_debugger_server(websocket, self.config['pid'], False) + logging.info(f'Connect to the debugger server of instance: {worker_thread_1.instance_id}') + ################################################################################################################ + # main thread: Debugger.resume + ################################################################################################################ + await self.debugger_impl.send("Debugger.resume", main_thread, websocket) + ################################################################################################################ + # worker thread: connect the debugger server + ################################################################################################################ + worker_thread_2 = await self.debugger_impl.connect_to_debugger_server(websocket, self.config['pid'], False) + logging.info(f'Connect to the debugger server of instance: {worker_thread_2.instance_id}') + ################################################################################################################ + # worker thread: Runtime.enable + ################################################################################################################ + await self.runtime_impl.send("Runtime.enable", worker_thread_1) + await self.runtime_impl.send("Runtime.enable", worker_thread_2) + ################################################################################################################ + # worker thread: Debugger.enable + ################################################################################################################ + await self.debugger_impl.send("Debugger.enable", worker_thread_1, websocket) + await self.debugger_impl.send("Debugger.enable", worker_thread_2, websocket) + ################################################################################################################ + # worker thread: Runtime.runIfWaitingForDebugger + ################################################################################################################ + # worker1 thread: Runtime.runIfWaitingForDebugger + await self.runtime_impl.send("Runtime.runIfWaitingForDebugger", worker_thread_1) + # worker1 thread: Debugger.scriptParsed + response = await self.debugger_impl.recv("Debugger.scriptParsed", worker_thread_1, websocket) + assert response['params']['url'] == self.config['file_path']['worker'] + assert response['params']['endLine'] == 0 + # worker1 thread: Debugger.paused + response = await self.debugger_impl.recv("Debugger.paused", worker_thread_1, websocket) + assert response['params']['callFrames'][0]['url'] == self.config['file_path']['worker'] + assert response['params']['reason'] == 'Break on start' + # worker2 thread: Runtime.runIfWaitingForDebugger + await self.runtime_impl.send("Runtime.runIfWaitingForDebugger", worker_thread_2) + # worker2 thread: Debugger.scriptParsed + response = await self.debugger_impl.recv("Debugger.scriptParsed", worker_thread_2, websocket) + assert response['params']['url'] == self.config['file_path']['worker'] + assert response['params']['endLine'] == 0 + # worker2 thread: Debugger.paused + response = await self.debugger_impl.recv("Debugger.paused", worker_thread_2, websocket) + assert response['params']['callFrames'][0]['url'] == self.config['file_path']['worker'] + assert response['params']['reason'] == 'Break on start' + ################################################################################################################ + # worker thread: Debugger.removeBreakpointsByUrl + ################################################################################################################ + params = debugger.RemoveBreakpointsUrl(self.config['file_path']['worker']) + await self.debugger_impl.send("Debugger.removeBreakpointsByUrl", worker_thread_1, websocket, params) + await self.debugger_impl.send("Debugger.removeBreakpointsByUrl", worker_thread_2, websocket, params) + ################################################################################################################ + # worker thread: Debugger.getPossibleAndSetBreakpointByUrl + ################################################################################################################ + locations = [debugger.BreakLocationUrl(url=self.config['file_path']['worker'], line_number=11)] + params = debugger.SetBreakpointsLocations(locations) + response = await self.debugger_impl.send("Debugger.getPossibleAndSetBreakpointsByUrl", + worker_thread_1, websocket, params) + assert response['result']['locations'][0]['id'] == 'id:11:0:' + self.config['file_path']['worker'] + response = await self.debugger_impl.send("Debugger.getPossibleAndSetBreakpointsByUrl", + worker_thread_2, websocket, params) + assert response['result']['locations'][0]['id'] == 'id:11:0:' + self.config['file_path']['worker'] + ################################################################################################################ + # worker thread: Debugger.resume + ################################################################################################################ + await self.debugger_impl.send("Debugger.resume", worker_thread_1, websocket) + await self.debugger_impl.send("Debugger.resume", worker_thread_2, websocket) + ################################################################################################################ + # main thread: click on the screen + ################################################################################################################ + Application.click_on_middle() + ################################################################################################################ + # main thread: Debugger.paused, hit breakpoint + ################################################################################################################ + response = await self.debugger_impl.recv("Debugger.paused", main_thread, websocket) + assert response['params']['callFrames'][0]['url'] == self.config['file_path']['index'] + assert response['params']['hitBreakpoints'] == ['id:53:16:' + self.config['file_path']['index']] + ################################################################################################################ + # worker thread: destroy instance + ################################################################################################################ + # worker thread 2 destroyed + response = await self.debugger_impl.destroy_instance(websocket) + assert response['type'] == 'destroyInstance' + ################################################################################################################ + # main thread: Debugger.stepInto + ################################################################################################################ + await self.debugger_impl.send("Debugger.stepInto", main_thread, websocket) + await self.debugger_impl.recv("Debugger.paused", main_thread, websocket) + ################################################################################################################ + # main thread: Runtime.getProperties + ################################################################################################################ + params = runtime.GetPropertiesParams('0', True, False, True) + response = await self.runtime_impl.send("Runtime.getProperties", main_thread, params) + assert response['result']['result'][0]['name'] == 'set message' + assert response['result']['result'][0]['value']['type'] == 'function' + assert response['result']['result'][1]['name'] == 'newValue' + assert response['result']['result'][1]['value']['type'] == 'string' + ################################################################################################################ + # main thread: Debugger.resume + ################################################################################################################ + await self.debugger_impl.send("Debugger.resume", main_thread, websocket) + ################################################################################################################ + # main thread: Debugger.paused, hit breakpoint + ################################################################################################################ + response = await self.debugger_impl.recv("Debugger.paused", main_thread, websocket) + assert response['params']['callFrames'][0]['url'] == self.config['file_path']['index'] + assert response['params']['hitBreakpoints'] == ['id:57:20:' + self.config['file_path']['index']] + ################################################################################################################ + # worker thread: connect the debugger server + ################################################################################################################ + worker_thread_2 = await self.debugger_impl.connect_to_debugger_server(websocket, self.config['pid'], False) + logging.info(f'Connect to the debugger server of instance: {worker_thread_2.instance_id}') + ################################################################################################################ + # worker thread: Runtime.enable + ################################################################################################################ + await self.runtime_impl.send("Runtime.enable", worker_thread_2) + ################################################################################################################ + # worker thread: Debugger.enable + ################################################################################################################ + await self.debugger_impl.send("Debugger.enable", worker_thread_2, websocket) + ################################################################################################################ + # worker thread: Runtime.runIfWaitingForDebugger + ################################################################################################################ + await self.runtime_impl.send("Runtime.runIfWaitingForDebugger", worker_thread_2) + response = await self.debugger_impl.recv("Debugger.scriptParsed", worker_thread_2, websocket) + assert response['params']['url'] == self.config['file_path']['worker'] + assert response['params']['endLine'] == 0 + response = await self.debugger_impl.recv("Debugger.paused", worker_thread_2, websocket) + assert response['params']['callFrames'][0]['url'] == self.config['file_path']['worker'] + assert response['params']['reason'] == 'Break on start' + ################################################################################################################ + # worker thread: Debugger.removeBreakpointsByUrl + ################################################################################################################ + params = debugger.RemoveBreakpointsUrl(self.config['file_path']['worker']) + await self.debugger_impl.send("Debugger.removeBreakpointsByUrl", worker_thread_2, websocket, params) + ################################################################################################################ + # worker thread: Debugger.getPossibleAndSetBreakpointByUrl + ################################################################################################################ + locations = [debugger.BreakLocationUrl(url=self.config['file_path']['worker'], line_number=11)] + params = debugger.SetBreakpointsLocations(locations) + response = await self.debugger_impl.send("Debugger.getPossibleAndSetBreakpointsByUrl", + worker_thread_2, websocket, params) + assert response['result']['locations'][0]['id'] == 'id:11:0:' + self.config['file_path']['worker'] + ################################################################################################################ + # worker thread: Debugger.resume + ################################################################################################################ + await self.debugger_impl.send("Debugger.resume", worker_thread_2, websocket) + ################################################################################################################ + # main thread: Debugger.resume + ################################################################################################################ + await self.debugger_impl.send("Debugger.resume", main_thread, websocket) + # main thread: Debugger.paused + response = await self.debugger_impl.recv("Debugger.paused", main_thread, websocket) + assert response['params']['callFrames'][0]['url'] == self.config['file_path']['index'] + assert response['params']['reason'] == 'other' + assert response['params']['hitBreakpoints'] == ['id:57:20:' + self.config['file_path']['index']] + # worker thread: Debugger.paused + response = await self.debugger_impl.recv("Debugger.paused", worker_thread_1, websocket) + assert response['params']['callFrames'][0]['url'] == self.config['file_path']['worker'] + assert response['params']['reason'] == 'other' + assert response['params']['hitBreakpoints'] == ['id:11:4:' + self.config['file_path']['worker']] + ################################################################################################################ + # worker thread: Runtime.getProperties + ################################################################################################################ + params = runtime.GetPropertiesParams('0', True, False, True) + response = await self.runtime_impl.send("Runtime.getProperties", worker_thread_1, params) + assert response['result']['result'][0]['name'] == '' + assert response['result']['result'][0]['value']['type'] == 'function' + assert response['result']['result'][1]['name'] == 'e' + assert response['result']['result'][1]['value']['type'] == 'object' + ################################################################################################################ + # worker thread: Debugger.stepOut + ################################################################################################################ + await self.debugger_impl.send("Debugger.stepOut", worker_thread_1, websocket) + ################################################################################################################ + # worker thread: Debugger.disable + ################################################################################################################ + await self.debugger_impl.send("Debugger.disable", worker_thread_1, websocket) + ################################################################################################################ + # main thread: Debugger.stepOver + ################################################################################################################ + await self.debugger_impl.send("Debugger.stepOver", main_thread, websocket) + # main thread: Debugger.paused + response = await self.debugger_impl.recv("Debugger.paused", main_thread, websocket) + assert response['params']['callFrames'][0]['url'] == self.config['file_path']['index'] + assert response['params']['reason'] == 'other' + assert response['params']['hitBreakpoints'] == [] + # worker thread: Debugger.paused + response = await self.debugger_impl.recv("Debugger.paused", worker_thread_2, websocket) + assert response['params']['callFrames'][0]['url'] == self.config['file_path']['worker'] + assert response['params']['reason'] == 'other' + assert response['params']['hitBreakpoints'] == ['id:11:4:' + self.config['file_path']['worker']] + ################################################################################################################ + # worker thread: Debugger.resume + ################################################################################################################ + await self.debugger_impl.send("Debugger.resume", worker_thread_2, websocket) + ################################################################################################################ + # worker thread: Debugger.disable + ################################################################################################################ + await self.debugger_impl.send("Debugger.disable", worker_thread_2, websocket) + ################################################################################################################ + # main thread: Debugger.resume + ################################################################################################################ + await self.debugger_impl.send("Debugger.resume", main_thread, websocket) + ################################################################################################################ + # worker thread: destroy instance + ################################################################################################################ + response = await self.debugger_impl.destroy_instance(websocket) + assert response['type'] == 'destroyInstance' + assert response['instanceId'] != self.config['pid'] + response = await self.debugger_impl.destroy_instance(websocket) + assert response['type'] == 'destroyInstance' + assert response['instanceId'] != self.config['pid'] + ################################################################################################################ + # main thread: Debugger.disable + ################################################################################################################ + await self.debugger_impl.send("Debugger.disable", main_thread, websocket) + ################################################################################################################ + # close the websocket connections + ################################################################################################################ + await websocket.send_msg_to_debugger_server(main_thread.instance_id, main_thread.send_msg_queue, 'close') + await websocket.send_msg_to_connect_server('close') + ################################################################################################################ \ No newline at end of file diff --git a/test/autotest/scenario_test/test_debug_02.py b/test/autotest/scenario_test/test_debug_02.py new file mode 100644 index 0000000000000000000000000000000000000000..e039a20975a32d25183546e193ae27000bf49fa5 --- /dev/null +++ b/test/autotest/scenario_test/test_debug_02.py @@ -0,0 +1,537 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +""" +Copyright (c) 2024 Huawei Device Co., Ltd. +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +Description: Scenario test case. +""" + +import json +import logging +import os +import time + +import pytest + +from aw import Application +from aw import Utils +from aw import communicate_with_debugger_server +from aw import debugger, runtime + + +@pytest.mark.debug +@pytest.mark.timeout(30) +class TestDebug02: + """ + 测试用例:多实例 attach 调试 + 测试步骤: + 1. 拉起应用,attach 主线程 + 2. 连接 connect server 和主线程 debugger server + 3. 创建两个子线程,连接子线程 debugger server + 4. 所有线程使能 Runtime 和 Debugger + 5. 主线程 Index.ts 文件设置断点(Debugger.getPossibleAndSetBreakpointByUrl) + 6. 触发点击事件,主线程命中断点 + 7. 销毁其中一个子线程 + 8. 子线程 Worker.ts 文件设置断点(Debugger.getPossibleAndSetBreakpointByUrl) + 9. 主线程 resume,暂停在下一断点(Debugger.resume) + 10. 重新创建一个子线程,使能并设置断点 + 11. 主线程 resume,发送消息给子线程,主线程暂停在下一断点(Debugger.resume) + 12. 子线程命中断点后 stepOut,发消息给主线程(Debugger.stepOut) + 13. 主线程 stepOver,发送消息给另一子线程,主线程暂停在下一行(Debugger.stepOver) + 14. 子线程命中断点后 resume,发消息给主线程(Debugger.resume) + 15. 销毁所有子线程,对应的 debugger server 连接断开 + 16. 关闭主线程 debugger server 和 connect server 连接 + """ + + def setup_method(self): + logging.info('Start running TestDebug02: setup') + + self.log_path = rf'{os.path.dirname(__file__)}\..\log' + self.hilog_file_name = 'test_debug_02.hilog.txt' + self.id_generator = Utils.message_id_generator() + + # receive the hilog before the test start + Utils.clear_fault_log() + self.hilog_process, self.write_thread = Utils.save_hilog(log_path=self.log_path, + file_name=self.hilog_file_name, + debug_on=True) + + def teardown_method(self): + Application.uninstall(self.config['bundle_name']) + + # terminate the hilog receive process after the test done + time.sleep(3) + self.hilog_process.stdout.close() + self.hilog_process.terminate() + self.hilog_process.wait() + self.write_thread.join() + + Utils.save_fault_log(log_path=self.log_path) + logging.info('TestDebug02 done') + + def test(self, test_suite_worker_01): + logging.info('Start running TestDebug02: test') + self.config = test_suite_worker_01 + websocket = self.config['websocket'] + taskpool = self.config['taskpool'] + pid = self.config['pid'] + + Application.attach(self.config['bundle_name']) + taskpool.submit(websocket.main_task(taskpool, websocket, self.procedure, pid)) + taskpool.await_taskpool() + taskpool.task_join() + if taskpool.task_exception: + raise taskpool.task_exception + + async def procedure(self, websocket): + ################################################################################################################ + # main thread: connect the debugger server + ################################################################################################################ + send_msg = {"type": "connected"} + await websocket.send_msg_to_connect_server(send_msg) + response = await websocket.recv_msg_of_connect_server() + response = json.loads(response) + assert response['type'] == 'addInstance' + assert response['instanceId'] == 0, logging.error('instance id of the main thread not equal to 0') + assert response['tid'] == self.config['pid'] + main_thread_instance_id = await websocket.get_instance() + main_thread_to_send_queue = websocket.to_send_msg_queues[main_thread_instance_id] + main_thread_received_queue = websocket.received_msg_queues[main_thread_instance_id] + logging.info(f'Connect to the debugger server of instance: {main_thread_instance_id}') + ################################################################################################################ + # worker thread: connect the debugger server + ################################################################################################################ + workers_num = 2 + worker_instances_id = [] + worker_thread_to_send_queues = [] + worker_thread_received_queues = [] + for i in range(workers_num): + response = await websocket.recv_msg_of_connect_server() + response = json.loads(response) + assert response['type'] == 'addInstance' + assert response['instanceId'] != 0 + assert response['tid'] != self.config['pid'] + assert 'workerThread_' in response['name'] + worker_instance_id = await websocket.get_instance() + worker_instances_id.append(worker_instance_id) + worker_thread_to_send_queues.append(websocket.to_send_msg_queues[worker_instance_id]) + worker_thread_received_queues.append(websocket.received_msg_queues[worker_instance_id]) + logging.info(f'Connect to the debugger server of instance: {worker_instance_id}') + ################################################################################################################ + # worker thread: Runtime.enable + ################################################################################################################ + for i in range(workers_num): + message_id = next(self.id_generator) + response = await communicate_with_debugger_server(worker_instances_id[i], + worker_thread_to_send_queues[i], + worker_thread_received_queues[i], + runtime.enable(), message_id) + assert json.loads(response) == {"id": message_id, "result": {"protocols": []}} + ################################################################################################################ + # worker thread: Debugger.enable + ################################################################################################################ + for i in range(workers_num): + message_id = next(self.id_generator) + response = await communicate_with_debugger_server(worker_instances_id[i], + worker_thread_to_send_queues[i], + worker_thread_received_queues[i], + debugger.enable(), message_id) + response = json.loads(response) + assert response['method'] == 'Debugger.scriptParsed' + assert response['params']['url'] == self.config['file_path']['worker'] + assert response['params']['endLine'] == 0 + response = await websocket.recv_msg_of_debugger_server(worker_instances_id[i], + worker_thread_received_queues[i]) + assert json.loads(response) == {"id": message_id, "result": {"debuggerId": "0", + "protocols": Utils.get_custom_protocols()}} + ################################################################################################################ + # worker thread: Runtime.runIfWaitingForDebugger + ################################################################################################################ + for i in range(workers_num): + message_id = next(self.id_generator) + response = await communicate_with_debugger_server(worker_instances_id[i], + worker_thread_to_send_queues[i], + worker_thread_received_queues[i], + runtime.run_if_waiting_for_debugger(), message_id) + assert json.loads(response) == {"id": message_id, "result": {}} + ################################################################################################################ + # main thread: Debugger.enable + ################################################################################################################ + message_id = next(self.id_generator) + response = await communicate_with_debugger_server(main_thread_instance_id, + main_thread_to_send_queue, + main_thread_received_queue, + debugger.enable(), message_id) + assert json.loads(response)['method'] == 'Debugger.scriptParsed' + response = await websocket.recv_msg_of_debugger_server(main_thread_instance_id, + main_thread_received_queue) + assert json.loads(response)['method'] == 'Debugger.scriptParsed' + response = await websocket.recv_msg_of_debugger_server(main_thread_instance_id, + main_thread_received_queue) + assert json.loads(response) == {"id": message_id, "result": {"debuggerId": "0", + "protocols": Utils.get_custom_protocols()}} + ################################################################################################################ + # main thread: Runtime.runIfWaitingForDebugger + ################################################################################################################ + message_id = next(self.id_generator) + response = await communicate_with_debugger_server(main_thread_instance_id, + main_thread_to_send_queue, + main_thread_received_queue, + runtime.run_if_waiting_for_debugger(), message_id) + assert json.loads(response) == {"id": message_id, "result": {}} + ################################################################################################################ + # main thread: Debugger.removeBreakpointsByUrl + ################################################################################################################ + message_id = next(self.id_generator) + response = await communicate_with_debugger_server(main_thread_instance_id, + main_thread_to_send_queue, + main_thread_received_queue, + debugger.remove_breakpoints_by_url( + self.config['file_path']['index']), + message_id) + assert json.loads(response) == {"id": message_id, "result": {}} + ################################################################################################################ + # main thread: Debugger.getPossibleAndSetBreakpointByUrl + ################################################################################################################ + message_id = next(self.id_generator) + locations = [debugger.BreakLocationUrl(url=self.config['file_path']['index'], line_number=53), + debugger.BreakLocationUrl(url=self.config['file_path']['index'], line_number=57)] + response = await communicate_with_debugger_server(main_thread_instance_id, + main_thread_to_send_queue, + main_thread_received_queue, + debugger.get_possible_and_set_breakpoint_by_url(locations), + message_id) + response = json.loads(response) + assert response['id'] == message_id + assert response['result']['locations'][0]['id'] == 'id:53:0:' + self.config['file_path']['index'] + assert response['result']['locations'][1]['id'] == 'id:57:0:' + self.config['file_path']['index'] + ################################################################################################################ + # main thread: click on the screen + ################################################################################################################ + Application.click_on_middle() + ################################################################################################################ + # main thread: Debugger.paused, hit breakpoint + ################################################################################################################ + response = await websocket.recv_msg_of_debugger_server(main_thread_instance_id, + main_thread_received_queue) + response = json.loads(response) + assert response['method'] == 'Debugger.paused' + assert response['params']['callFrames'][0]['url'] == self.config['file_path']['index'] + assert response['params']['hitBreakpoints'] == ['id:53:16:' + self.config['file_path']['index']] + ################################################################################################################ + # worker thread: destroy instance + ################################################################################################################ + response = await websocket.recv_msg_of_connect_server() + response = json.loads(response) + assert response['type'] == 'destroyInstance' + if response['instanceId'] == worker_instances_id[0]: + worker_instances_id[0] = worker_instances_id[1] + worker_thread_to_send_queues[0] = worker_thread_to_send_queues[1] + worker_thread_received_queues[0] = worker_thread_received_queues[1] + ################################################################################################################ + # worker thread: Debugger.removeBreakpointsByUrl + ################################################################################################################ + message_id = next(self.id_generator) + response = await communicate_with_debugger_server(worker_instances_id[0], + worker_thread_to_send_queues[0], + worker_thread_received_queues[0], + debugger.remove_breakpoints_by_url( + self.config['file_path']['worker']), + message_id) + assert json.loads(response) == {"id": message_id, "result": {}} + ################################################################################################################ + # worker thread: Debugger.getPossibleAndSetBreakpointByUrl + ################################################################################################################ + message_id = next(self.id_generator) + locations = [debugger.BreakLocationUrl(url=self.config['file_path']['worker'], line_number=11)] + response = await communicate_with_debugger_server(worker_instances_id[0], + worker_thread_to_send_queues[0], + worker_thread_received_queues[0], + debugger.get_possible_and_set_breakpoint_by_url(locations), + message_id) + response = json.loads(response) + assert response['id'] == message_id + assert response['result']['locations'][0]['id'] == 'id:11:0:' + self.config['file_path']['worker'] + ################################################################################################################ + # main thread: Debugger.resume + ################################################################################################################ + message_id = next(self.id_generator) + response = await communicate_with_debugger_server(main_thread_instance_id, + main_thread_to_send_queue, + main_thread_received_queue, + debugger.resume(), message_id) + assert json.loads(response) == {"method": "Debugger.resumed", "params": {}} + response = await websocket.recv_msg_of_debugger_server(main_thread_instance_id, + main_thread_received_queue) + assert json.loads(response) == {"id": message_id, "result": {}} + ################################################################################################################ + # main thread: Debugger.paused, hit breakpoint + ################################################################################################################ + response = await websocket.recv_msg_of_debugger_server(main_thread_instance_id, + main_thread_received_queue) + response = json.loads(response) + assert response['method'] == 'Debugger.paused' + assert response['params']['callFrames'][0]['url'] == self.config['file_path']['index'] + assert response['params']['hitBreakpoints'] == ['id:57:20:' + self.config['file_path']['index']] + ################################################################################################################ + # worker thread: connect the debugger server + ################################################################################################################ + response = await websocket.recv_msg_of_connect_server() + response = json.loads(response) + assert response['type'] == 'addInstance' + assert response['instanceId'] != 0 + assert response['tid'] != self.config['pid'] + assert 'workerThread_' in response['name'] + worker_instances_id[1] = await websocket.get_instance() + worker_thread_to_send_queues[1] = websocket.to_send_msg_queues[worker_instances_id[1]] + worker_thread_received_queues[1] = websocket.received_msg_queues[worker_instances_id[1]] + logging.info(f'Connect to the debugger server of instance: {worker_instances_id[1]}') + ################################################################################################################ + # worker thread: Runtime.enable + ################################################################################################################ + message_id = next(self.id_generator) + response = await communicate_with_debugger_server(worker_instances_id[1], + worker_thread_to_send_queues[1], + worker_thread_received_queues[1], + runtime.enable(), message_id) + assert json.loads(response) == {"id": message_id, "result": {"protocols": []}} + ################################################################################################################ + # worker thread: Debugger.enable + ################################################################################################################ + message_id = next(self.id_generator) + response = await communicate_with_debugger_server(worker_instances_id[1], + worker_thread_to_send_queues[1], + worker_thread_received_queues[1], + debugger.enable(), message_id) + assert json.loads(response) == {"id": message_id, "result": {"debuggerId": "0", + "protocols": Utils.get_custom_protocols()}} + ################################################################################################################ + # worker thread: Runtime.runIfWaitingForDebugger + ################################################################################################################ + message_id = next(self.id_generator) + response = await communicate_with_debugger_server(worker_instances_id[1], + worker_thread_to_send_queues[1], + worker_thread_received_queues[1], + runtime.run_if_waiting_for_debugger(), message_id) + assert json.loads(response) == {"id": message_id, "result": {}} + response = await websocket.recv_msg_of_debugger_server(worker_instances_id[1], + worker_thread_received_queues[1]) + response = json.loads(response) + assert response['method'] == 'Debugger.scriptParsed' + assert response['params']['url'] == self.config['file_path']['worker'] + assert response['params']['endLine'] == 0 + ################################################################################################################ + # worker thread: Debugger.removeBreakpointsByUrl + ################################################################################################################ + message_id = next(self.id_generator) + response = await communicate_with_debugger_server(worker_instances_id[1], + worker_thread_to_send_queues[1], + worker_thread_received_queues[1], + debugger.remove_breakpoints_by_url( + self.config['file_path']['worker']), + message_id) + response = json.loads(response) + assert response['method'] == 'Debugger.paused' + assert response['params']['callFrames'][0]['url'] == self.config['file_path']['worker'] + assert response['params']['reason'] == 'Break on start' + response = await websocket.recv_msg_of_debugger_server(worker_instances_id[1], + worker_thread_received_queues[1]) + assert json.loads(response) == {"id": message_id, "result": {}} + ################################################################################################################ + # worker thread: Debugger.getPossibleAndSetBreakpointByUrl + ################################################################################################################ + message_id = next(self.id_generator) + locations = [debugger.BreakLocationUrl(url=self.config['file_path']['worker'], line_number=11)] + response = await communicate_with_debugger_server(worker_instances_id[1], + worker_thread_to_send_queues[1], + worker_thread_received_queues[1], + debugger.get_possible_and_set_breakpoint_by_url(locations), + message_id) + response = json.loads(response) + assert response['id'] == message_id + assert response['result']['locations'][0]['id'] == 'id:11:0:' + self.config['file_path']['worker'] + ################################################################################################################ + # worker thread: Debugger.resume + ################################################################################################################ + message_id = next(self.id_generator) + response = await communicate_with_debugger_server(worker_instances_id[1], + worker_thread_to_send_queues[1], + worker_thread_received_queues[1], + debugger.resume(), message_id) + assert json.loads(response) == {"method": "Debugger.resumed", "params": {}} + response = await websocket.recv_msg_of_debugger_server(worker_instances_id[1], + worker_thread_received_queues[1]) + assert json.loads(response) == {"id": message_id, "result": {}} + ################################################################################################################ + # main thread: Debugger.resume + ################################################################################################################ + message_id = next(self.id_generator) + response = await communicate_with_debugger_server(main_thread_instance_id, + main_thread_to_send_queue, + main_thread_received_queue, + debugger.resume(), message_id) + assert json.loads(response) == {"method": "Debugger.resumed", "params": {}} + response = await websocket.recv_msg_of_debugger_server(main_thread_instance_id, + main_thread_received_queue) + assert json.loads(response) == {"id": message_id, "result": {}} + # main thread: Debugger.paused + response = await websocket.recv_msg_of_debugger_server(main_thread_instance_id, + main_thread_received_queue) + response = json.loads(response) + assert response['method'] == 'Debugger.paused' + assert response['params']['callFrames'][0]['url'] == self.config['file_path']['index'] + assert response['params']['reason'] == 'other' + assert response['params']['hitBreakpoints'] == ['id:57:20:' + self.config['file_path']['index']] + # worker thread: Debugger.paused + response = await websocket.recv_msg_of_debugger_server(worker_instances_id[0], + worker_thread_received_queues[0]) + response = json.loads(response) + assert response['method'] == 'Debugger.paused' + assert response['params']['callFrames'][0]['url'] == self.config['file_path']['worker'] + assert response['params']['reason'] == 'Break on start' + assert response['params']['hitBreakpoints'] == [] + ################################################################################################################ + # worker thread: Debugger.resume + ################################################################################################################ + message_id = next(self.id_generator) + response = await communicate_with_debugger_server(worker_instances_id[0], + worker_thread_to_send_queues[0], + worker_thread_received_queues[0], + debugger.resume(), message_id) + assert json.loads(response) == {"method": "Debugger.resumed", "params": {}} + response = await websocket.recv_msg_of_debugger_server(worker_instances_id[0], + worker_thread_received_queues[0]) + assert json.loads(response) == {"id": message_id, "result": {}} + # worker thread: Debugger.paused + response = await websocket.recv_msg_of_debugger_server(worker_instances_id[0], + worker_thread_received_queues[0]) + response = json.loads(response) + assert response['method'] == 'Debugger.paused' + assert response['params']['callFrames'][0]['url'] == self.config['file_path']['worker'] + assert response['params']['reason'] == 'other' + assert response['params']['hitBreakpoints'] == ['id:11:4:' + self.config['file_path']['worker']] + ################################################################################################################ + # worker thread: Debugger.stepOut + ################################################################################################################ + message_id = next(self.id_generator) + response = await communicate_with_debugger_server(worker_instances_id[0], + worker_thread_to_send_queues[0], + worker_thread_received_queues[0], + debugger.step_out(), message_id) + assert json.loads(response) == {"method": "Debugger.resumed", "params": {}} + response = await websocket.recv_msg_of_debugger_server(worker_instances_id[0], + worker_thread_received_queues[0]) + assert json.loads(response) == {"id": message_id, "result": {}} + ################################################################################################################ + # worker thread: Debugger.disable + ################################################################################################################ + message_id = next(self.id_generator) + response = await communicate_with_debugger_server(worker_instances_id[0], + worker_thread_to_send_queues[0], + worker_thread_received_queues[0], + debugger.disable(), message_id) + assert json.loads(response) == {"method": "Debugger.resumed", "params": {}} + response = await websocket.recv_msg_of_debugger_server(worker_instances_id[0], + worker_thread_received_queues[0]) + assert json.loads(response) == {"id": message_id, "result": {}} + ################################################################################################################ + # main thread: Debugger.stepOver + ################################################################################################################ + message_id = next(self.id_generator) + response = await communicate_with_debugger_server(main_thread_instance_id, + main_thread_to_send_queue, + main_thread_received_queue, + debugger.step_over(), message_id) + assert json.loads(response) == {"method": "Debugger.resumed", "params": {}} + response = await websocket.recv_msg_of_debugger_server(main_thread_instance_id, + main_thread_received_queue) + assert json.loads(response) == {"id": message_id, "result": {}} + # main thread: Debugger.paused + response = await websocket.recv_msg_of_debugger_server(main_thread_instance_id, + main_thread_received_queue) + response = json.loads(response) + assert response['method'] == 'Debugger.paused' + assert response['params']['callFrames'][0]['url'] == self.config['file_path']['index'] + assert response['params']['reason'] == 'other' + assert response['params']['hitBreakpoints'] == [] + # worker thread: Debugger.paused + response = await websocket.recv_msg_of_debugger_server(worker_instances_id[1], + worker_thread_received_queues[1]) + response = json.loads(response) + assert response['method'] == 'Debugger.paused' + assert response['params']['callFrames'][0]['url'] == self.config['file_path']['worker'] + assert response['params']['reason'] == 'other' + assert response['params']['hitBreakpoints'] == ['id:11:4:' + self.config['file_path']['worker']] + ################################################################################################################ + # worker thread: Debugger.resume + ################################################################################################################ + message_id = next(self.id_generator) + response = await communicate_with_debugger_server(worker_instances_id[1], + worker_thread_to_send_queues[1], + worker_thread_received_queues[1], + debugger.resume(), message_id) + assert json.loads(response) == {"method": "Debugger.resumed", "params": {}} + response = await websocket.recv_msg_of_debugger_server(worker_instances_id[1], + worker_thread_received_queues[1]) + assert json.loads(response) == {"id": message_id, "result": {}} + ################################################################################################################ + # worker thread: Debugger.disable + ################################################################################################################ + message_id = next(self.id_generator) + response = await communicate_with_debugger_server(worker_instances_id[1], + worker_thread_to_send_queues[1], + worker_thread_received_queues[1], + debugger.disable(), message_id) + assert json.loads(response) == {"method": "Debugger.resumed", "params": {}} + response = await websocket.recv_msg_of_debugger_server(worker_instances_id[1], + worker_thread_received_queues[1]) + assert json.loads(response) == {"id": message_id, "result": {}} + ################################################################################################################ + # main thread: Debugger.resume + ################################################################################################################ + message_id = next(self.id_generator) + response = await communicate_with_debugger_server(main_thread_instance_id, + main_thread_to_send_queue, + main_thread_received_queue, + debugger.resume(), message_id) + assert json.loads(response) == {"method": "Debugger.resumed", "params": {}} + response = await websocket.recv_msg_of_debugger_server(main_thread_instance_id, + main_thread_received_queue) + assert json.loads(response) == {"id": message_id, "result": {}} + ################################################################################################################ + # worker thread: destroy instance + ################################################################################################################ + for i in range(workers_num): + response = await websocket.recv_msg_of_connect_server() + response = json.loads(response) + assert response['type'] == 'destroyInstance' + assert response['instanceId'] in worker_instances_id + ################################################################################################################ + # main thread: Debugger.disable + ################################################################################################################ + message_id = next(self.id_generator) + response = await communicate_with_debugger_server(main_thread_instance_id, + main_thread_to_send_queue, + main_thread_received_queue, + debugger.disable(), message_id) + assert json.loads(response) == {"method": "Debugger.resumed", "params": {}} + response = await websocket.recv_msg_of_debugger_server(main_thread_instance_id, + main_thread_received_queue) + assert json.loads(response) == {"id": message_id, "result": {}} + ################################################################################################################ + # close the websocket connections + ################################################################################################################ + await websocket.send_msg_to_debugger_server(main_thread_instance_id, main_thread_to_send_queue, 'close') + await websocket.send_msg_to_connect_server('close') + ################################################################################################################ \ No newline at end of file diff --git a/test/autotest/scenario_test/test_debug_03.py b/test/autotest/scenario_test/test_debug_03.py new file mode 100644 index 0000000000000000000000000000000000000000..0c631b865ad4baa43b62231bf30780b67b198ec0 --- /dev/null +++ b/test/autotest/scenario_test/test_debug_03.py @@ -0,0 +1,431 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +""" +Copyright (c) 2024 Huawei Device Co., Ltd. +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +Description: Scenario test case. +""" + +import json +import logging +import os +import time + +import pytest + +from aw import Application +from aw import Utils +from aw import communicate_with_debugger_server +from aw import debugger, runtime + + +@pytest.mark.debug +@pytest.mark.timeout(30) +class TestDebug03: + """ + 测试用例:多 task 实例 debug 调试 + 测试步骤: + 1. 连接 connect server 和主线程 debugger server + 2. 主线程使能 Runtime 和 Debugger + 3. 连接子线程 debugger server,用于执行 task 任务 + 4. 子线程使能 Runtime 和 Debugger + 5. 主线程 Index.ts 文件设置断点(Debugger.getPossibleAndSetBreakpointByUrl) + 6. 触发点击事件,主线程命中断点 + 7. 子线程 Index.ts 文件设置断点(Debugger.getPossibleAndSetBreakpointByUrl) + 8. 子线程 resume,命中断点(Debugger.resume) + 9. 子线程 getProperties,返回给定对象的属性(Runtime.getProperties) + 10. 子线程 stepOut,主线程命中断点(Debugger.stepOut) + 11. 主线程 getProperties(Runtime.getProperties) + 12. 主线程 resume(Debugger.resume) + 13. 子线程命中断点后 resume(Debugger.resume) + 14. 关闭所有线程 debugger server 和 connect server 连接 + """ + + def setup_method(self): + logging.info('Start running TestDebug03: setup') + + self.log_path = rf'{os.path.dirname(__file__)}\..\log' + self.hilog_file_name = 'test_debug_03.hilog.txt' + self.id_generator = Utils.message_id_generator() + + # receive the hilog before the test start + Utils.clear_fault_log() + self.hilog_process, self.write_thread = Utils.save_hilog(log_path=self.log_path, + file_name=self.hilog_file_name, + debug_on=True) + + def teardown_method(self): + Application.uninstall(self.config['bundle_name']) + + # terminate the hilog receive process after the test done + time.sleep(3) + self.hilog_process.stdout.close() + self.hilog_process.terminate() + self.hilog_process.wait() + self.write_thread.join() + + Utils.save_fault_log(log_path=self.log_path) + logging.info('TestDebug03 done') + + def test(self, test_suite_taskpool_01_debug): + logging.info('Start running TestDebug03: test') + self.config = test_suite_taskpool_01_debug + websocket = self.config['websocket'] + taskpool = self.config['taskpool'] + pid = self.config['pid'] + + taskpool.submit(websocket.main_task(taskpool, websocket, self.procedure, pid)) + taskpool.await_taskpool() + taskpool.task_join() + if taskpool.task_exception: + raise taskpool.task_exception + + async def procedure(self, websocket): + ################################################################################################################ + # main thread: connect the debugger server + ################################################################################################################ + send_msg = {"type": "connected"} + await websocket.send_msg_to_connect_server(send_msg) + response = await websocket.recv_msg_of_connect_server() + response = json.loads(response) + assert response['type'] == 'addInstance' + assert response['instanceId'] == 0, logging.error('instance id of the main thread not equal to 0') + assert response['tid'] == self.config['pid'] + main_thread_instance_id = await websocket.get_instance() + main_thread_to_send_queue = websocket.to_send_msg_queues[main_thread_instance_id] + main_thread_received_queue = websocket.received_msg_queues[main_thread_instance_id] + logging.info(f'Connect to the debugger server of instance: {main_thread_instance_id}') + ################################################################################################################ + # main thread: Runtime.enable + ################################################################################################################ + message_id = next(self.id_generator) + response = await communicate_with_debugger_server(main_thread_instance_id, + main_thread_to_send_queue, + main_thread_received_queue, + runtime.enable(), message_id) + assert json.loads(response) == {"id": message_id, "result": {"protocols": []}} + ################################################################################################################ + # main thread: Debugger.enable + ################################################################################################################ + message_id = next(self.id_generator) + response = await communicate_with_debugger_server(main_thread_instance_id, + main_thread_to_send_queue, + main_thread_received_queue, + debugger.enable(), message_id) + assert json.loads(response) == {"id": message_id, "result": {"debuggerId": "0", + "protocols": Utils.get_custom_protocols()}} + ################################################################################################################ + # main thread: Runtime.runIfWaitingForDebugger + ################################################################################################################ + message_id = next(self.id_generator) + response = await communicate_with_debugger_server(main_thread_instance_id, + main_thread_to_send_queue, + main_thread_received_queue, + runtime.run_if_waiting_for_debugger(), message_id) + assert json.loads(response) == {"id": message_id, "result": {}} + ################################################################################################################ + # main thread: Debugger.scriptParsed + ################################################################################################################ + response = await websocket.recv_msg_of_debugger_server(main_thread_instance_id, + main_thread_received_queue) + response = json.loads(response) + assert response['method'] == 'Debugger.scriptParsed' + assert response['params']['url'] == self.config['file_path']['entry_ability'] + assert response['params']['endLine'] == 0 + ################################################################################################################ + # main thread: Debugger.paused + ################################################################################################################ + response = await websocket.recv_msg_of_debugger_server(main_thread_instance_id, + main_thread_received_queue) + response = json.loads(response) + assert response['method'] == 'Debugger.paused' + assert response['params']['callFrames'][0]['url'] == self.config['file_path']['entry_ability'] + assert response['params']['reason'] == 'Break on start' + ################################################################################################################ + # main thread: Debugger.resume + ################################################################################################################ + message_id = next(self.id_generator) + response = await communicate_with_debugger_server(main_thread_instance_id, + main_thread_to_send_queue, + main_thread_received_queue, + debugger.resume(), message_id) + assert json.loads(response) == {"method": "Debugger.resumed", "params": {}} + response = await websocket.recv_msg_of_debugger_server(main_thread_instance_id, + main_thread_received_queue) + assert json.loads(response) == {"id": message_id, "result": {}} + ################################################################################################################ + # main thread: Debugger.scriptParsed + ################################################################################################################ + response = await websocket.recv_msg_of_debugger_server(main_thread_instance_id, + main_thread_received_queue) + response = json.loads(response) + assert response['method'] == 'Debugger.scriptParsed' + assert response['params']['url'] == self.config['file_path']['index'] + assert response['params']['endLine'] == 0 + ################################################################################################################ + # main thread: Debugger.paused + ################################################################################################################ + response = await websocket.recv_msg_of_debugger_server(main_thread_instance_id, + main_thread_received_queue) + response = json.loads(response) + assert response['method'] == 'Debugger.paused' + assert response['params']['callFrames'][0]['url'] == self.config['file_path']['index'] + assert response['params']['reason'] == 'Break on start' + ################################################################################################################ + # main thread: Debugger.resume + ################################################################################################################ + message_id = next(self.id_generator) + response = await communicate_with_debugger_server(main_thread_instance_id, + main_thread_to_send_queue, + main_thread_received_queue, + debugger.resume(), message_id) + assert json.loads(response) == {"method": "Debugger.resumed", "params": {}} + response = await websocket.recv_msg_of_debugger_server(main_thread_instance_id, + main_thread_received_queue) + assert json.loads(response) == {"id": message_id, "result": {}} + ################################################################################################################ + # worker thread: connect the debugger server + ################################################################################################################ + response = await websocket.recv_msg_of_connect_server() + response = json.loads(response) + assert response['type'] == 'addInstance' + assert response['instanceId'] != 0 + assert response['tid'] != self.config['pid'] + assert 'workerThread_' in response['name'] + worker_instance_id = await websocket.get_instance() + worker_thread_to_send_queue = websocket.to_send_msg_queues[worker_instance_id] + worker_thread_received_queue = websocket.received_msg_queues[worker_instance_id] + logging.info(f'Connect to the debugger server of instance: {worker_instance_id}') + ################################################################################################################ + # worker thread: Runtime.enable + ################################################################################################################ + message_id = next(self.id_generator) + response = await communicate_with_debugger_server(worker_instance_id, + worker_thread_to_send_queue, + worker_thread_received_queue, + runtime.enable(), message_id) + assert json.loads(response) == {"id": message_id, "result": {"protocols": []}} + ################################################################################################################ + # worker thread: Debugger.enable + ################################################################################################################ + message_id = next(self.id_generator) + response = await communicate_with_debugger_server(worker_instance_id, + worker_thread_to_send_queue, + worker_thread_received_queue, + debugger.enable(), message_id) + assert json.loads(response) == {"id": message_id, "result": {"debuggerId": "0", + "protocols": Utils.get_custom_protocols()}} + ################################################################################################################ + # worker thread: Runtime.runIfWaitingForDebugger + ################################################################################################################ + message_id = next(self.id_generator) + response = await communicate_with_debugger_server(worker_instance_id, + worker_thread_to_send_queue, + worker_thread_received_queue, + runtime.run_if_waiting_for_debugger(), message_id) + assert json.loads(response) == {"id": message_id, "result": {}} + ################################################################################################################ + # main thread: Debugger.removeBreakpointsByUrl + ################################################################################################################ + message_id = next(self.id_generator) + response = await communicate_with_debugger_server(main_thread_instance_id, + main_thread_to_send_queue, + main_thread_received_queue, + debugger.remove_breakpoints_by_url( + self.config['file_path']['index']), + message_id) + assert json.loads(response) == {"id": message_id, "result": {}} + ################################################################################################################ + # main thread: Debugger.getPossibleAndSetBreakpointByUrl + ################################################################################################################ + message_id = next(self.id_generator) + locations = [debugger.BreakLocationUrl(url=self.config['file_path']['index'], line_number=10), + debugger.BreakLocationUrl(url=self.config['file_path']['index'], line_number=17), + debugger.BreakLocationUrl(url=self.config['file_path']['index'], line_number=25)] + response = await communicate_with_debugger_server(main_thread_instance_id, + main_thread_to_send_queue, + main_thread_received_queue, + debugger.get_possible_and_set_breakpoint_by_url(locations), + message_id) + response = json.loads(response) + assert response['id'] == message_id + assert response['result']['locations'][0]['id'] == 'id:10:0:' + self.config['file_path']['index'] + assert response['result']['locations'][1]['id'] == 'id:17:0:' + self.config['file_path']['index'] + assert response['result']['locations'][2]['id'] == 'id:25:0:' + self.config['file_path']['index'] + ################################################################################################################ + # main thread: click on the screen + ################################################################################################################ + Application.click_on_middle() + ################################################################################################################ + # worker thread: Debugger.scriptParsed + ################################################################################################################ + response = await websocket.recv_msg_of_debugger_server(worker_instance_id, + worker_thread_received_queue) + response = json.loads(response) + assert response['method'] == 'Debugger.scriptParsed' + assert response['params']['url'] == self.config['file_path']['index'] + assert response['params']['endLine'] == 0 + # worker thread: Debugger.paused + response = await websocket.recv_msg_of_debugger_server(worker_instance_id, + worker_thread_received_queue) + response = json.loads(response) + assert response['method'] == 'Debugger.paused' + assert response['params']['callFrames'][0]['url'] == self.config['file_path']['index'] + assert response['params']['reason'] == 'Break on start' + ################################################################################################################ + # worker thread: Debugger.removeBreakpointsByUrl + ################################################################################################################ + message_id = next(self.id_generator) + response = await communicate_with_debugger_server(worker_instance_id, + worker_thread_to_send_queue, + worker_thread_received_queue, + debugger.remove_breakpoints_by_url( + self.config['file_path']['index']), + message_id) + assert json.loads(response) == {"id": message_id, "result": {}} + ################################################################################################################ + # worker thread: Debugger.getPossibleAndSetBreakpointByUrl + ################################################################################################################ + message_id = next(self.id_generator) + locations = [debugger.BreakLocationUrl(url=self.config['file_path']['index'], line_number=10), + debugger.BreakLocationUrl(url=self.config['file_path']['index'], line_number=17), + debugger.BreakLocationUrl(url=self.config['file_path']['index'], line_number=25)] + response = await communicate_with_debugger_server(worker_instance_id, + worker_thread_to_send_queue, + worker_thread_received_queue, + debugger.get_possible_and_set_breakpoint_by_url(locations), + message_id) + response = json.loads(response) + assert response['id'] == message_id + assert response['result']['locations'][0]['id'] == 'id:10:0:' + self.config['file_path']['index'] + assert response['result']['locations'][1]['id'] == 'id:17:0:' + self.config['file_path']['index'] + assert response['result']['locations'][2]['id'] == 'id:25:0:' + self.config['file_path']['index'] + ################################################################################################################ + # worker thread: Debugger.resume + ################################################################################################################ + message_id = next(self.id_generator) + response = await communicate_with_debugger_server(worker_instance_id, + worker_thread_to_send_queue, + worker_thread_received_queue, + debugger.resume(), message_id) + assert json.loads(response) == {"method": "Debugger.resumed", "params": {}} + response = await websocket.recv_msg_of_debugger_server(worker_instance_id, + worker_thread_received_queue) + assert json.loads(response) == {"id": message_id, "result": {}} + # worker thread: Debugger.paused + response = await websocket.recv_msg_of_debugger_server(worker_instance_id, + worker_thread_received_queue) + response = json.loads(response) + assert response['method'] == 'Debugger.paused' + assert response['params']['callFrames'][0]['url'] == self.config['file_path']['index'] + assert response['params']['reason'] == 'other' + assert response['params']['hitBreakpoints'] == ['id:10:14:' + self.config['file_path']['index']] + ################################################################################################################ + # worker thread: Runtime.getProperties + ################################################################################################################ + message_id = next(self.id_generator) + response = await communicate_with_debugger_server(worker_instance_id, + worker_thread_to_send_queue, + worker_thread_received_queue, + runtime.get_properties(object_id='0', + own_properties=True, + accessor_properties_only=False, + generate_preview=True), + message_id) + response = json.loads(response) + assert response['id'] == message_id + assert response['result']['result'][0]['name'] == 'add' + assert response['result']['result'][0]['value']['type'] == 'function' + ################################################################################################################ + # worker thread: Debugger.stepOut + ################################################################################################################ + message_id = next(self.id_generator) + response = await communicate_with_debugger_server(worker_instance_id, + worker_thread_to_send_queue, + worker_thread_received_queue, + debugger.step_out(), message_id) + assert json.loads(response) == {"method": "Debugger.resumed", "params": {}} + response = await websocket.recv_msg_of_debugger_server(worker_instance_id, + worker_thread_received_queue) + assert json.loads(response) == {"id": message_id, "result": {}} + ################################################################################################################ + # main thread: Debugger.paused, hit breakpoint + ################################################################################################################ + response = await websocket.recv_msg_of_debugger_server(main_thread_instance_id, + main_thread_received_queue) + response = json.loads(response) + assert response['method'] == 'Debugger.paused' + assert response['params']['callFrames'][0]['url'] == self.config['file_path']['index'] + assert response['params']['hitBreakpoints'] == ['id:25:4:' + self.config['file_path']['index']] + ################################################################################################################ + # main thread: Runtime.getProperties + ################################################################################################################ + message_id = next(self.id_generator) + response = await communicate_with_debugger_server(main_thread_instance_id, + main_thread_to_send_queue, + main_thread_received_queue, + runtime.get_properties(object_id='0', + own_properties=True, + accessor_properties_only=False, + generate_preview=True), + message_id) + response = json.loads(response) + assert response['id'] == message_id + assert response['result']['result'][0]['name'] == 'taskpoolTest' + assert response['result']['result'][0]['value']['type'] == 'function' + assert response['result']['result'][1]['name'] == 'valueSub' + assert response['result']['result'][1]['value']['type'] == 'undefined' + assert response['result']['result'][2]['name'] == 'valueAdd' + assert response['result']['result'][2]['value']['type'] == 'number' + assert response['result']['result'][2]['value']['description'] == '300' + ################################################################################################################ + # main thread: Debugger.resume + ################################################################################################################ + message_id = next(self.id_generator) + response = await communicate_with_debugger_server(main_thread_instance_id, + main_thread_to_send_queue, + main_thread_received_queue, + debugger.resume(), message_id) + assert json.loads(response) == {"method": "Debugger.resumed", "params": {}} + response = await websocket.recv_msg_of_debugger_server(main_thread_instance_id, + main_thread_received_queue) + assert json.loads(response) == {"id": message_id, "result": {}} + ################################################################################################################ + # worker thread: Debugger.paused + ################################################################################################################ + response = await websocket.recv_msg_of_debugger_server(worker_instance_id, + worker_thread_received_queue) + response = json.loads(response) + assert response['method'] == 'Debugger.paused' + assert response['params']['callFrames'][0]['url'] == self.config['file_path']['index'] + assert response['params']['hitBreakpoints'] == ['id:17:14:' + self.config['file_path']['index']] + ################################################################################################################ + # worker thread: Debugger.resume + ################################################################################################################ + message_id = next(self.id_generator) + response = await communicate_with_debugger_server(worker_instance_id, + worker_thread_to_send_queue, + worker_thread_received_queue, + debugger.resume(), message_id) + assert json.loads(response) == {"method": "Debugger.resumed", "params": {}} + response = await websocket.recv_msg_of_debugger_server(worker_instance_id, + worker_thread_received_queue) + assert json.loads(response) == {"id": message_id, "result": {}} + ################################################################################################################ + # close the websocket connections + ################################################################################################################ + await websocket.send_msg_to_debugger_server(worker_instance_id, worker_thread_to_send_queue, 'close') + await websocket.send_msg_to_debugger_server(main_thread_instance_id, main_thread_to_send_queue, 'close') + await websocket.send_msg_to_connect_server('close') + ################################################################################################################ \ No newline at end of file diff --git a/test/autotest/scenario_test/test_debug_04.py b/test/autotest/scenario_test/test_debug_04.py new file mode 100644 index 0000000000000000000000000000000000000000..60b68fcbfe99cd8687a9b17cab1e823c4a1ac7d1 --- /dev/null +++ b/test/autotest/scenario_test/test_debug_04.py @@ -0,0 +1,384 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +""" +Copyright (c) 2024 Huawei Device Co., Ltd. +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +Description: Scenario test case. +""" + +import json +import logging +import os +import time + +import pytest + +from aw import Application +from aw import Utils +from aw import communicate_with_debugger_server +from aw import debugger, runtime + + +@pytest.mark.debug +@pytest.mark.timeout(30) +class TestDebug04: + """ + 测试用例:多 task 实例 attach 调试 + 测试步骤: + 1. 连接 connect server 和主线程 debugger server + 2. 连接子线程 debugger server,用于执行 task 任务 + 3. 所有线程使能 Runtime 和 Debugger + 4. 主线程 Index.ts 文件设置断点(Debugger.getPossibleAndSetBreakpointByUrl) + 5. 触发点击事件,主线程命中断点 + 6. 子线程 Index.ts 文件设置断点(Debugger.getPossibleAndSetBreakpointByUrl) + 7. 子线程 resume,命中断点(Debugger.resume) + 8. 子线程 getProperties,返回给定对象的属性(Runtime.getProperties) + 9. 子线程 stepOut,主线程命中断点(Debugger.stepOut) + 10. 主线程 getProperties(Runtime.getProperties) + 11. 主线程 resume(Debugger.resume) + 11. 子线程命中断点后 resume(Debugger.resume) + 12. 关闭所有线程 debugger server 和 connect server 连接 + """ + + def setup_method(self): + logging.info('Start running TestDebug04: setup') + + self.log_path = rf'{os.path.dirname(__file__)}\..\log' + self.hilog_file_name = 'test_debug_04.hilog.txt' + self.id_generator = Utils.message_id_generator() + + # receive the hilog before the test start + Utils.clear_fault_log() + self.hilog_process, self.write_thread = Utils.save_hilog(log_path=self.log_path, + file_name=self.hilog_file_name, + debug_on=True) + + def teardown_method(self): + Application.uninstall(self.config['bundle_name']) + + # terminate the hilog receive process after the test done + time.sleep(3) + self.hilog_process.stdout.close() + self.hilog_process.terminate() + self.hilog_process.wait() + self.write_thread.join() + + Utils.save_fault_log(log_path=self.log_path) + logging.info('TestDebug04 done') + + def test(self, test_suite_taskpool_01): + logging.info('Start running TestDebug04: test') + self.config = test_suite_taskpool_01 + websocket = self.config['websocket'] + taskpool = self.config['taskpool'] + pid = self.config['pid'] + + Application.attach(self.config['bundle_name']) + taskpool.submit(websocket.main_task(taskpool, websocket, self.procedure, pid)) + taskpool.await_taskpool() + taskpool.task_join() + if taskpool.task_exception: + raise taskpool.task_exception + + async def procedure(self, websocket): + ################################################################################################################ + # main thread: connect the debugger server + ################################################################################################################ + send_msg = {"type": "connected"} + await websocket.send_msg_to_connect_server(send_msg) + response = await websocket.recv_msg_of_connect_server() + response = json.loads(response) + assert response['type'] == 'addInstance' + assert response['instanceId'] == 0, logging.error('instance id of the main thread not equal to 0') + assert response['tid'] == self.config['pid'] + main_thread_instance_id = await websocket.get_instance() + main_thread_to_send_queue = websocket.to_send_msg_queues[main_thread_instance_id] + main_thread_received_queue = websocket.received_msg_queues[main_thread_instance_id] + logging.info(f'Connect to the debugger server of instance: {main_thread_instance_id}') + ################################################################################################################ + # worker thread: connect the debugger server + ################################################################################################################ + response = await websocket.recv_msg_of_connect_server() + response = json.loads(response) + assert response['type'] == 'addInstance' + assert response['instanceId'] != 0 + assert response['tid'] != self.config['pid'] + assert 'workerThread_' in response['name'] + worker_instance_id = await websocket.get_instance() + worker_thread_to_send_queue = websocket.to_send_msg_queues[worker_instance_id] + worker_thread_received_queue = websocket.received_msg_queues[worker_instance_id] + logging.info(f'Connect to the debugger server of instance: {worker_instance_id}') + ################################################################################################################ + # main thread: Runtime.enable + ################################################################################################################ + message_id = next(self.id_generator) + response = await communicate_with_debugger_server(main_thread_instance_id, + main_thread_to_send_queue, + main_thread_received_queue, + runtime.enable(), message_id) + assert json.loads(response) == {"id": message_id, "result": {"protocols": []}} + ################################################################################################################ + # worker thread: Runtime.enable + ################################################################################################################ + message_id = next(self.id_generator) + response = await communicate_with_debugger_server(worker_instance_id, + worker_thread_to_send_queue, + worker_thread_received_queue, + runtime.enable(), message_id) + assert json.loads(response) == {"id": message_id, "result": {"protocols": []}} + ################################################################################################################ + # main thread: Debugger.enable + ################################################################################################################ + message_id = next(self.id_generator) + response = await communicate_with_debugger_server(main_thread_instance_id, + main_thread_to_send_queue, + main_thread_received_queue, + debugger.enable(), message_id) + # main thread: Debugger.scriptParsed + response = json.loads(response) + assert response['method'] == 'Debugger.scriptParsed' + assert response['params']['url'] == self.config['file_path']['index'] + assert response['params']['endLine'] == 0 + response = await websocket.recv_msg_of_debugger_server(main_thread_instance_id, + main_thread_received_queue) + response = json.loads(response) + assert response['method'] == 'Debugger.scriptParsed' + assert response['params']['url'] == self.config['file_path']['entry_ability'] + assert response['params']['endLine'] == 0 + response = await websocket.recv_msg_of_debugger_server(main_thread_instance_id, + main_thread_received_queue) + assert json.loads(response) == {"id": message_id, "result": {"debuggerId": "0", + "protocols": Utils.get_custom_protocols()}} + ################################################################################################################ + # main thread: Runtime.runIfWaitingForDebugger + ################################################################################################################ + message_id = next(self.id_generator) + response = await communicate_with_debugger_server(main_thread_instance_id, + main_thread_to_send_queue, + main_thread_received_queue, + runtime.run_if_waiting_for_debugger(), message_id) + assert json.loads(response) == {"id": message_id, "result": {}} + ################################################################################################################ + # worker thread: Debugger.enable + ################################################################################################################ + message_id = next(self.id_generator) + response = await communicate_with_debugger_server(worker_instance_id, + worker_thread_to_send_queue, + worker_thread_received_queue, + debugger.enable(), message_id) + assert json.loads(response) == {"id": message_id, "result": {"debuggerId": "0", + "protocols": Utils.get_custom_protocols()}} + ################################################################################################################ + # worker thread: Runtime.runIfWaitingForDebugger + ################################################################################################################ + message_id = next(self.id_generator) + response = await communicate_with_debugger_server(worker_instance_id, + worker_thread_to_send_queue, + worker_thread_received_queue, + runtime.run_if_waiting_for_debugger(), message_id) + assert json.loads(response) == {"id": message_id, "result": {}} + ################################################################################################################ + # main thread: Debugger.removeBreakpointsByUrl + ################################################################################################################ + message_id = next(self.id_generator) + response = await communicate_with_debugger_server(main_thread_instance_id, + main_thread_to_send_queue, + main_thread_received_queue, + debugger.remove_breakpoints_by_url( + self.config['file_path']['index']), + message_id) + assert json.loads(response) == {"id": message_id, "result": {}} + ################################################################################################################ + # main thread: Debugger.getPossibleAndSetBreakpointByUrl + ################################################################################################################ + message_id = next(self.id_generator) + locations = [debugger.BreakLocationUrl(url=self.config['file_path']['index'], line_number=10), + debugger.BreakLocationUrl(url=self.config['file_path']['index'], line_number=17), + debugger.BreakLocationUrl(url=self.config['file_path']['index'], line_number=25)] + response = await communicate_with_debugger_server(main_thread_instance_id, + main_thread_to_send_queue, + main_thread_received_queue, + debugger.get_possible_and_set_breakpoint_by_url(locations), + message_id) + response = json.loads(response) + assert response['id'] == message_id + assert response['result']['locations'][0]['id'] == 'id:10:0:' + self.config['file_path']['index'] + assert response['result']['locations'][1]['id'] == 'id:17:0:' + self.config['file_path']['index'] + assert response['result']['locations'][2]['id'] == 'id:25:0:' + self.config['file_path']['index'] + ################################################################################################################ + # main thread: click on the screen + ################################################################################################################ + Application.click_on_middle() + ################################################################################################################ + # worker thread: Debugger.scriptParsed + ################################################################################################################ + response = await websocket.recv_msg_of_debugger_server(worker_instance_id, + worker_thread_received_queue) + response = json.loads(response) + assert response['method'] == 'Debugger.scriptParsed' + assert response['params']['url'] == self.config['file_path']['index'] + assert response['params']['endLine'] == 0 + # worker thread: Debugger.paused + response = await websocket.recv_msg_of_debugger_server(worker_instance_id, + worker_thread_received_queue) + response = json.loads(response) + assert response['method'] == 'Debugger.paused' + assert response['params']['callFrames'][0]['url'] == self.config['file_path']['index'] + assert response['params']['reason'] == 'Break on start' + ################################################################################################################ + # worker thread: Debugger.removeBreakpointsByUrl + ################################################################################################################ + message_id = next(self.id_generator) + response = await communicate_with_debugger_server(worker_instance_id, + worker_thread_to_send_queue, + worker_thread_received_queue, + debugger.remove_breakpoints_by_url( + self.config['file_path']['index']), + message_id) + assert json.loads(response) == {"id": message_id, "result": {}} + ################################################################################################################ + # worker thread: Debugger.getPossibleAndSetBreakpointByUrl + ################################################################################################################ + message_id = next(self.id_generator) + locations = [debugger.BreakLocationUrl(url=self.config['file_path']['index'], line_number=10), + debugger.BreakLocationUrl(url=self.config['file_path']['index'], line_number=17), + debugger.BreakLocationUrl(url=self.config['file_path']['index'], line_number=25)] + response = await communicate_with_debugger_server(worker_instance_id, + worker_thread_to_send_queue, + worker_thread_received_queue, + debugger.get_possible_and_set_breakpoint_by_url(locations), + message_id) + response = json.loads(response) + assert response['id'] == message_id + assert response['result']['locations'][0]['id'] == 'id:10:0:' + self.config['file_path']['index'] + assert response['result']['locations'][1]['id'] == 'id:17:0:' + self.config['file_path']['index'] + assert response['result']['locations'][2]['id'] == 'id:25:0:' + self.config['file_path']['index'] + ################################################################################################################ + # worker thread: Debugger.resume + ################################################################################################################ + message_id = next(self.id_generator) + response = await communicate_with_debugger_server(worker_instance_id, + worker_thread_to_send_queue, + worker_thread_received_queue, + debugger.resume(), message_id) + assert json.loads(response) == {"method": "Debugger.resumed", "params": {}} + response = await websocket.recv_msg_of_debugger_server(worker_instance_id, + worker_thread_received_queue) + assert json.loads(response) == {"id": message_id, "result": {}} + # worker thread: Debugger.paused + response = await websocket.recv_msg_of_debugger_server(worker_instance_id, + worker_thread_received_queue) + response = json.loads(response) + assert response['method'] == 'Debugger.paused' + assert response['params']['callFrames'][0]['url'] == self.config['file_path']['index'] + assert response['params']['reason'] == 'other' + assert response['params']['hitBreakpoints'] == ['id:10:14:' + self.config['file_path']['index']] + ################################################################################################################ + # worker thread: Runtime.getProperties + ################################################################################################################ + message_id = next(self.id_generator) + response = await communicate_with_debugger_server(worker_instance_id, + worker_thread_to_send_queue, + worker_thread_received_queue, + runtime.get_properties(object_id='0', + own_properties=True, + accessor_properties_only=False, + generate_preview=True), + message_id) + response = json.loads(response) + assert response['id'] == message_id + assert response['result']['result'][0]['name'] == 'add' + assert response['result']['result'][0]['value']['type'] == 'function' + ################################################################################################################ + # worker thread: Debugger.stepOut + ################################################################################################################ + message_id = next(self.id_generator) + response = await communicate_with_debugger_server(worker_instance_id, + worker_thread_to_send_queue, + worker_thread_received_queue, + debugger.step_out(), message_id) + assert json.loads(response) == {"method": "Debugger.resumed", "params": {}} + response = await websocket.recv_msg_of_debugger_server(worker_instance_id, + worker_thread_received_queue) + assert json.loads(response) == {"id": message_id, "result": {}} + ################################################################################################################ + # main thread: Debugger.paused, hit breakpoint + ################################################################################################################ + response = await websocket.recv_msg_of_debugger_server(main_thread_instance_id, + main_thread_received_queue) + response = json.loads(response) + assert response['method'] == 'Debugger.paused' + assert response['params']['callFrames'][0]['url'] == self.config['file_path']['index'] + assert response['params']['hitBreakpoints'] == ['id:25:4:' + self.config['file_path']['index']] + ################################################################################################################ + # main thread: Runtime.getProperties + ################################################################################################################ + message_id = next(self.id_generator) + response = await communicate_with_debugger_server(main_thread_instance_id, + main_thread_to_send_queue, + main_thread_received_queue, + runtime.get_properties(object_id='0', + own_properties=True, + accessor_properties_only=False, + generate_preview=True), + message_id) + response = json.loads(response) + assert response['id'] == message_id + assert response['result']['result'][0]['name'] == 'taskpoolTest' + assert response['result']['result'][0]['value']['type'] == 'function' + assert response['result']['result'][1]['name'] == 'valueSub' + assert response['result']['result'][1]['value']['type'] == 'undefined' + assert response['result']['result'][2]['name'] == 'valueAdd' + assert response['result']['result'][2]['value']['type'] == 'number' + assert response['result']['result'][2]['value']['description'] == '300' + ################################################################################################################ + # main thread: Debugger.resume + ################################################################################################################ + message_id = next(self.id_generator) + response = await communicate_with_debugger_server(main_thread_instance_id, + main_thread_to_send_queue, + main_thread_received_queue, + debugger.resume(), message_id) + assert json.loads(response) == {"method": "Debugger.resumed", "params": {}} + response = await websocket.recv_msg_of_debugger_server(main_thread_instance_id, + main_thread_received_queue) + assert json.loads(response) == {"id": message_id, "result": {}} + ################################################################################################################ + # worker thread: Debugger.paused + ################################################################################################################ + response = await websocket.recv_msg_of_debugger_server(worker_instance_id, + worker_thread_received_queue) + response = json.loads(response) + assert response['method'] == 'Debugger.paused' + assert response['params']['callFrames'][0]['url'] == self.config['file_path']['index'] + assert response['params']['hitBreakpoints'] == ['id:17:14:' + self.config['file_path']['index']] + ################################################################################################################ + # worker thread: Debugger.resume + ################################################################################################################ + message_id = next(self.id_generator) + response = await communicate_with_debugger_server(worker_instance_id, + worker_thread_to_send_queue, + worker_thread_received_queue, + debugger.resume(), message_id) + assert json.loads(response) == {"method": "Debugger.resumed", "params": {}} + response = await websocket.recv_msg_of_debugger_server(worker_instance_id, + worker_thread_received_queue) + assert json.loads(response) == {"id": message_id, "result": {}} + ################################################################################################################ + # close the websocket connections + ################################################################################################################ + await websocket.send_msg_to_debugger_server(worker_instance_id, worker_thread_to_send_queue, 'close') + await websocket.send_msg_to_debugger_server(main_thread_instance_id, main_thread_to_send_queue, 'close') + await websocket.send_msg_to_connect_server('close') + ################################################################################################################ \ No newline at end of file diff --git a/test/autotest/scenario_test/test_heap_profiler_01.py b/test/autotest/scenario_test/test_heap_profiler_01.py new file mode 100644 index 0000000000000000000000000000000000000000..438efabfc5a92ed45066422255d7a1ca7b504ec2 --- /dev/null +++ b/test/autotest/scenario_test/test_heap_profiler_01.py @@ -0,0 +1,300 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +""" +Copyright (c) 2024 Huawei Device Co., Ltd. +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +Description: Scenario test case. +""" + +import json +import logging +import os +import time + +import pytest + +from aw import Application +from aw import Utils +from aw import communicate_with_debugger_server +from aw import debugger, runtime, heap_profiler + + +@pytest.mark.heap_profiler +@pytest.mark.timeout(40) +class TestHeapProfiler01: + """ + 测试用例:多实例内存调优 Allocation 录制 + 测试步骤: + 1. 拉起应用,attach 主线程 + 2. 连接 connect server 和主线程 debugger server + 3. 连接 worker 线程 debugger server + 4. 所有线程使能 Runtime(Runtime.enable) + 5. 所有线程获取内存使用情况(Runtime.getHeapUsage) + 6. 所有线程启动 Allocation 录制(HeapProfiler.startTrackingHeapObjects) + 7. 所有线程获取内存使用情况(Runtime.getHeapUsage) + 8. 等待 10 秒后关闭 Allocation 录制,获取数据(HeapProfiler.stopTrackingHeapObjects) + 9. 销毁 worker 线程,对应的 debugger server 连接断开 + 10. 关闭主线程 debugger server 和 connect server 连接 + """ + + def setup_method(self): + logging.info('Start running TestHeapProfiler01: setup') + + self.log_path = rf'{os.path.dirname(__file__)}\..\log' + self.hilog_file_name = 'test_heap_profiler_01.hilog.txt' + self.id_generator = Utils.message_id_generator() + + # receive the hilog before the test start + Utils.clear_fault_log() + self.hilog_process, self.write_thread = Utils.save_hilog(log_path=self.log_path, + file_name=self.hilog_file_name, + debug_on=True) + + def teardown_method(self): + Application.uninstall(self.config['bundle_name']) + + # terminate the hilog receive process after the test done + time.sleep(3) + self.hilog_process.stdout.close() + self.hilog_process.terminate() + self.hilog_process.wait() + self.write_thread.join() + + Utils.save_fault_log(log_path=self.log_path) + logging.info('TestHeapProfiler01 done') + + def test(self, test_suite_worker_02): + logging.info('Start running TestHeapProfiler01: test') + self.config = test_suite_worker_02 + websocket = self.config['websocket'] + taskpool = self.config['taskpool'] + pid = self.config['pid'] + + Application.attach(self.config['bundle_name']) + taskpool.submit(websocket.main_task(taskpool, websocket, self.procedure, pid)) + taskpool.await_taskpool() + taskpool.task_join() + if taskpool.task_exception: + raise taskpool.task_exception + + async def procedure(self, websocket): + ################################################################################################################ + # main thread: connect the debugger server + ################################################################################################################ + send_msg = {"type": "connected"} + await websocket.send_msg_to_connect_server(send_msg) + response = await websocket.recv_msg_of_connect_server() + response = json.loads(response) + assert response['type'] == 'addInstance' + assert response['instanceId'] == 0, logging.error('instance id of the main thread not equal to 0') + assert response['tid'] == self.config['pid'] + main_thread_instance_id = await websocket.get_instance() + main_thread_to_send_queue = websocket.to_send_msg_queues[main_thread_instance_id] + main_thread_received_queue = websocket.received_msg_queues[main_thread_instance_id] + logging.info(f'Connect to the debugger server of instance: {main_thread_instance_id}') + ################################################################################################################ + # worker thread: connect the debugger server + ################################################################################################################ + workers_num = 2 + worker_instances_id = [] + worker_thread_to_send_queues = [] + worker_thread_received_queues = [] + for i in range(workers_num): + response = await websocket.recv_msg_of_connect_server() + response = json.loads(response) + assert response['type'] == 'addInstance' + assert response['instanceId'] != 0 + assert response['tid'] != self.config['pid'] + assert 'workerThread_' in response['name'] + worker_instance_id = await websocket.get_instance() + worker_instances_id.append(worker_instance_id) + worker_thread_to_send_queues.append(websocket.to_send_msg_queues[worker_instance_id]) + worker_thread_received_queues.append(websocket.received_msg_queues[worker_instance_id]) + logging.info(f'Connect to the debugger server of instance: {worker_instance_id}') + ################################################################################################################ + # main thread: Runtime.enable + ################################################################################################################ + message_id = next(self.id_generator) + response = await communicate_with_debugger_server(main_thread_instance_id, + main_thread_to_send_queue, + main_thread_received_queue, + runtime.enable(), message_id) + assert json.loads(response) == {"id": message_id, "result": {"protocols": []}} + ################################################################################################################ + # worker thread: Runtime.enable + ################################################################################################################ + for i in range(workers_num): + message_id = next(self.id_generator) + response = await communicate_with_debugger_server(worker_instances_id[i], + worker_thread_to_send_queues[i], + worker_thread_received_queues[i], + runtime.enable(), message_id) + assert json.loads(response) == {"id": message_id, "result": {"protocols": []}} + ################################################################################################################ + # main thread: Runtime.getHeapUsage + ################################################################################################################ + message_id = next(self.id_generator) + response = await communicate_with_debugger_server(main_thread_instance_id, + main_thread_to_send_queue, + main_thread_received_queue, + runtime.get_heap_usage(), message_id) + response = json.loads(response) + assert response['result']['usedSize'] > 0 + assert response['result']['totalSize'] > 0 + ################################################################################################################ + # worker thread: Runtime.getHeapUsage + ################################################################################################################ + for i in range(workers_num): + message_id = next(self.id_generator) + response = await communicate_with_debugger_server(worker_instances_id[i], + worker_thread_to_send_queues[i], + worker_thread_received_queues[i], + runtime.get_heap_usage(), message_id) + response = json.loads(response) + assert response['result']['usedSize'] > 0 + assert response['result']['totalSize'] > 0 + ################################################################################################################ + # main thread: HeapProfiler.startTrackingHeapObjects + ################################################################################################################ + message_id = next(self.id_generator) + response = await communicate_with_debugger_server(main_thread_instance_id, + main_thread_to_send_queue, + main_thread_received_queue, + heap_profiler.start_tracking_heap_objects(False), + message_id) + assert json.loads(response) == {"id": message_id, "result": {}} + ################################################################################################################ + # worker thread: HeapProfiler.startTrackingHeapObjects + ################################################################################################################ + for i in range(workers_num): + message_id = next(self.id_generator) + response = await communicate_with_debugger_server(worker_instances_id[i], + worker_thread_to_send_queues[i], + worker_thread_received_queues[i], + heap_profiler.start_tracking_heap_objects(False), + message_id) + assert json.loads(response) == {"id": message_id, "result": {}} + ################################################################################################################ + # main thread: Debugger.disable + ################################################################################################################ + message_id = next(self.id_generator) + response = await communicate_with_debugger_server(main_thread_instance_id, + main_thread_to_send_queue, + main_thread_received_queue, + debugger.disable(), message_id) + while not json.loads(response).get('id', None): + response = await websocket.recv_msg_of_debugger_server(main_thread_instance_id, + main_thread_received_queue) + assert json.loads(response) == {"id": message_id, "result": {}} + ################################################################################################################ + # worker thread: Debugger.disable + ################################################################################################################ + for i in range(workers_num): + message_id = next(self.id_generator) + response = await communicate_with_debugger_server(worker_instances_id[i], + worker_thread_to_send_queues[i], + worker_thread_received_queues[i], + debugger.disable(), message_id) + while not json.loads(response).get('id', None): + response = await websocket.recv_msg_of_debugger_server(worker_instances_id[i], + worker_thread_received_queues[i]) + assert json.loads(response) == {"id": message_id, "result": {}} + ################################################################################################################ + # all thread: sleep 10 seconds + ################################################################################################################ + time.sleep(10) + ################################################################################################################ + # main thread: Runtime.getHeapUsage + ################################################################################################################ + message_id = next(self.id_generator) + response = await communicate_with_debugger_server(main_thread_instance_id, + main_thread_to_send_queue, + main_thread_received_queue, + runtime.get_heap_usage(), message_id) + while response.startswith('{"method":"HeapProfiler.lastSeenObjectId"'): + response = await websocket.recv_msg_of_debugger_server(main_thread_instance_id, + main_thread_received_queue) + response = json.loads(response) + assert response['result']['usedSize'] > 0 + assert response['result']['totalSize'] > 0 + ################################################################################################################ + # worker thread: Runtime.getHeapUsage + ################################################################################################################ + for i in range(workers_num): + message_id = next(self.id_generator) + response = await communicate_with_debugger_server(worker_instances_id[i], + worker_thread_to_send_queues[i], + worker_thread_received_queues[i], + runtime.get_heap_usage(), message_id) + while response.startswith('{"method":"HeapProfiler.lastSeenObjectId"'): + response = await websocket.recv_msg_of_debugger_server(worker_instances_id[i], + worker_thread_received_queues[i]) + response = json.loads(response) + assert response['result']['usedSize'] > 0 + assert response['result']['totalSize'] > 0 + ################################################################################################################ + # main thread: HeapProfiler.stopTrackingHeapObjects + ################################################################################################################ + message_id = next(self.id_generator) + response = await communicate_with_debugger_server(main_thread_instance_id, + main_thread_to_send_queue, + main_thread_received_queue, + heap_profiler.stop_tracking_heap_objects(), message_id) + while response.startswith('{"method":"HeapProfiler.lastSeenObjectId"'): + response = await websocket.recv_msg_of_debugger_server(main_thread_instance_id, + main_thread_received_queue) + assert r'\"location_fields\":[\"object_index\",\"script_id\",\"line\",\"column\"]' in response + pre_response = response + while response.startswith('{"method":"HeapProfiler.addHeapSnapshotChunk"') or\ + response.startswith('{"method":"HeapProfiler.lastSeenObjectId"'): + if response.startswith('{"method":"HeapProfiler.addHeapSnapshotChunk"'): + pre_response = response + response = await websocket.recv_msg_of_debugger_server(main_thread_instance_id, + main_thread_received_queue) + assert pre_response.endswith(r'\n]\n}\n"}}') + assert json.loads(response) == {"id": message_id, "result": {}} + ################################################################################################################ + # worker thread: HeapProfiler.stopTrackingHeapObjects + ################################################################################################################ + for i in range(workers_num): + message_id = next(self.id_generator) + response = await communicate_with_debugger_server(worker_instances_id[i], + worker_thread_to_send_queues[i], + worker_thread_received_queues[i], + heap_profiler.stop_tracking_heap_objects(), message_id) + while response.startswith('{"method":"HeapProfiler.lastSeenObjectId"'): + response = await websocket.recv_msg_of_debugger_server(worker_instances_id[i], + worker_thread_received_queues[i]) + assert r'\"location_fields\":[\"object_index\",\"script_id\",\"line\",\"column\"]' in response + pre_response = response + while response.startswith('{"method":"HeapProfiler.addHeapSnapshotChunk"') or\ + response.startswith('{"method":"HeapProfiler.lastSeenObjectId"'): + if response.startswith('{"method":"HeapProfiler.addHeapSnapshotChunk"'): + pre_response = response + response = await websocket.recv_msg_of_debugger_server(worker_instances_id[i], + worker_thread_received_queues[i]) + assert pre_response.endswith(r'\n]\n}\n"}}') + assert json.loads(response) == {"id": message_id, "result": {}} + ################################################################################################################ + # worker thread: destroy instance + ################################################################################################################ + for i in range(workers_num): + await websocket.send_msg_to_debugger_server(worker_instances_id[i], + worker_thread_to_send_queues[i], 'close') + ################################################################################################################ + # close the websocket connections + ################################################################################################################ + await websocket.send_msg_to_debugger_server(main_thread_instance_id, main_thread_to_send_queue, 'close') + await websocket.send_msg_to_connect_server('close') + ################################################################################################################ \ No newline at end of file diff --git a/test/autotest/scenario_test/test_heap_profiler_02.py b/test/autotest/scenario_test/test_heap_profiler_02.py new file mode 100644 index 0000000000000000000000000000000000000000..77aee0a20132c74dcd34a6f182dae1177e894190 --- /dev/null +++ b/test/autotest/scenario_test/test_heap_profiler_02.py @@ -0,0 +1,246 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +""" +Copyright (c) 2024 Huawei Device Co., Ltd. +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +Description: Scenario test case. +""" + +import json +import logging +import os +import time + +import pytest + +from aw import Application +from aw import Utils +from aw import communicate_with_debugger_server +from aw import debugger, runtime, heap_profiler + + +@pytest.mark.heap_profiler +@pytest.mark.timeout(40) +class TestHeapProfiler02: + """ + 测试用例:多实例内存调优 HeapDump 录制 + 测试步骤: + 1. 拉起应用,attach 主线程 + 2. 连接 connect server 和主线程 debugger server + 3. 连接 worker 线程 debugger server + 4. 所有线程使能 Runtime(Runtime.enable) + 5. 所有线程去使能 Debugger(Debugger.disable) + 5. 所有线程拍摄内存快照(HeapProfiler.takeHeapSnapshot) + 6. 等待 10 秒后,所有线程再次拍摄内存快照(HeapProfiler.takeHeapSnapshot) + 7. 销毁 worker 线程,对应的 debugger server 连接断开 + 8. 关闭主线程 debugger server 和 connect server 连接 + """ + + def setup_method(self): + logging.info('Start running TestHeapProfiler02: setup') + + self.log_path = rf'{os.path.dirname(__file__)}\..\log' + self.hilog_file_name = 'test_heap_profiler_02.hilog.txt' + self.id_generator = Utils.message_id_generator() + + # receive the hilog before the test start + Utils.clear_fault_log() + self.hilog_process, self.write_thread = Utils.save_hilog(log_path=self.log_path, + file_name=self.hilog_file_name, + debug_on=True) + + def teardown_method(self): + Application.uninstall(self.config['bundle_name']) + + # terminate the hilog receive process after the test done + time.sleep(3) + self.hilog_process.stdout.close() + self.hilog_process.terminate() + self.hilog_process.wait() + self.write_thread.join() + + Utils.save_fault_log(log_path=self.log_path) + logging.info('TestHeapProfiler02 done') + + def test(self, test_suite_worker_02): + logging.info('Start running TestHeapProfiler02: test') + self.config = test_suite_worker_02 + websocket = self.config['websocket'] + taskpool = self.config['taskpool'] + pid = self.config['pid'] + + Application.attach(self.config['bundle_name']) + taskpool.submit(websocket.main_task(taskpool, websocket, self.procedure, pid)) + taskpool.await_taskpool() + taskpool.task_join() + if taskpool.task_exception: + raise taskpool.task_exception + + async def procedure(self, websocket): + ################################################################################################################ + # main thread: connect the debugger server + ################################################################################################################ + send_msg = {"type": "connected"} + await websocket.send_msg_to_connect_server(send_msg) + response = await websocket.recv_msg_of_connect_server() + response = json.loads(response) + assert response['type'] == 'addInstance' + assert response['instanceId'] == 0, logging.error('instance id of the main thread not equal to 0') + assert response['tid'] == self.config['pid'] + main_thread_instance_id = await websocket.get_instance() + main_thread_to_send_queue = websocket.to_send_msg_queues[main_thread_instance_id] + main_thread_received_queue = websocket.received_msg_queues[main_thread_instance_id] + logging.info(f'Connect to the debugger server of instance: {main_thread_instance_id}') + ################################################################################################################ + # worker thread: connect the debugger server + ################################################################################################################ + workers_num = 2 + worker_instances_id = [] + worker_thread_to_send_queues = [] + worker_thread_received_queues = [] + for i in range(workers_num): + response = await websocket.recv_msg_of_connect_server() + response = json.loads(response) + assert response['type'] == 'addInstance' + assert response['instanceId'] != 0 + assert response['tid'] != self.config['pid'] + assert 'workerThread_' in response['name'] + worker_instance_id = await websocket.get_instance() + worker_instances_id.append(worker_instance_id) + worker_thread_to_send_queues.append(websocket.to_send_msg_queues[worker_instance_id]) + worker_thread_received_queues.append(websocket.received_msg_queues[worker_instance_id]) + logging.info(f'Connect to the debugger server of instance: {worker_instance_id}') + ################################################################################################################ + # main thread: Runtime.enable + ################################################################################################################ + message_id = next(self.id_generator) + response = await communicate_with_debugger_server(main_thread_instance_id, + main_thread_to_send_queue, + main_thread_received_queue, + runtime.enable(), message_id) + assert json.loads(response) == {"id": message_id, "result": {"protocols": []}} + ################################################################################################################ + # worker thread: Runtime.enable + ################################################################################################################ + for i in range(workers_num): + message_id = next(self.id_generator) + response = await communicate_with_debugger_server(worker_instances_id[i], + worker_thread_to_send_queues[i], + worker_thread_received_queues[i], + runtime.enable(), message_id) + assert json.loads(response) == {"id": message_id, "result": {"protocols": []}} + ################################################################################################################ + # main thread: Debugger.disable + ################################################################################################################ + message_id = next(self.id_generator) + response = await communicate_with_debugger_server(main_thread_instance_id, + main_thread_to_send_queue, + main_thread_received_queue, + debugger.disable(), message_id) + assert json.loads(response) == {"id": message_id, "result": {}} + ################################################################################################################ + # worker thread: Debugger.disable + ################################################################################################################ + for i in range(workers_num): + message_id = next(self.id_generator) + response = await communicate_with_debugger_server(worker_instances_id[i], + worker_thread_to_send_queues[i], + worker_thread_received_queues[i], + debugger.disable(), message_id) + while not json.loads(response).get('id', None): + response = await websocket.recv_msg_of_debugger_server(worker_instances_id[i], + worker_thread_received_queues[i]) + assert json.loads(response) == {"id": message_id, "result": {}} + ################################################################################################################ + # main thread: HeapProfiler.takeHeapSnapshot + ################################################################################################################ + message_id = next(self.id_generator) + response = await communicate_with_debugger_server(main_thread_instance_id, + main_thread_to_send_queue, + main_thread_received_queue, + heap_profiler.take_heap_snapshot(), message_id) + assert r'\"location_fields\":[\"object_index\",\"script_id\",\"line\",\"column\"]' in response + pre_response = response + while response.startswith('{"method":"HeapProfiler.addHeapSnapshotChunk"'): + pre_response = response + response = await websocket.recv_msg_of_debugger_server(main_thread_instance_id, + main_thread_received_queue) + assert pre_response.endswith(r'\n]\n}\n"}}') + assert json.loads(response) == {"id": message_id, "result": {}} + ################################################################################################################ + # worker thread: HeapProfiler.takeHeapSnapshot + ################################################################################################################ + for i in range(workers_num): + message_id = next(self.id_generator) + response = await communicate_with_debugger_server(worker_instances_id[i], + worker_thread_to_send_queues[i], + worker_thread_received_queues[i], + heap_profiler.take_heap_snapshot(), message_id) + assert r'\"location_fields\":[\"object_index\",\"script_id\",\"line\",\"column\"]' in response + pre_response = response + while response.startswith('{"method":"HeapProfiler.addHeapSnapshotChunk"'): + pre_response = response + response = await websocket.recv_msg_of_debugger_server(worker_instances_id[i], + worker_thread_received_queues[i]) + assert pre_response.endswith(r'\n]\n}\n"}}') + assert json.loads(response) == {"id": message_id, "result": {}} + ################################################################################################################ + # all thread: sleep 10 seconds + ################################################################################################################ + time.sleep(10) + ################################################################################################################ + # main thread: HeapProfiler.takeHeapSnapshot + ################################################################################################################ + message_id = next(self.id_generator) + response = await communicate_with_debugger_server(main_thread_instance_id, + main_thread_to_send_queue, + main_thread_received_queue, + heap_profiler.take_heap_snapshot(), message_id) + assert r'\"location_fields\":[\"object_index\",\"script_id\",\"line\",\"column\"]' in response + pre_response = response + while response.startswith('{"method":"HeapProfiler.addHeapSnapshotChunk"'): + pre_response = response + response = await websocket.recv_msg_of_debugger_server(main_thread_instance_id, + main_thread_received_queue) + assert pre_response.endswith(r'\n]\n}\n"}}') + assert json.loads(response) == {"id": message_id, "result": {}} + ################################################################################################################ + # worker thread: HeapProfiler.takeHeapSnapshot + ################################################################################################################ + for i in range(workers_num): + message_id = next(self.id_generator) + response = await communicate_with_debugger_server(worker_instances_id[i], + worker_thread_to_send_queues[i], + worker_thread_received_queues[i], + heap_profiler.take_heap_snapshot(), message_id) + assert r'\"location_fields\":[\"object_index\",\"script_id\",\"line\",\"column\"]' in response + pre_response = response + while response.startswith('{"method":"HeapProfiler.addHeapSnapshotChunk"'): + pre_response = response + response = await websocket.recv_msg_of_debugger_server(worker_instances_id[i], + worker_thread_received_queues[i]) + assert pre_response.endswith(r'\n]\n}\n"}}') + assert json.loads(response) == {"id": message_id, "result": {}} + ################################################################################################################ + # worker thread: destroy instance + ################################################################################################################ + for i in range(workers_num): + await websocket.send_msg_to_debugger_server(worker_instances_id[i], + worker_thread_to_send_queues[i], 'close') + ################################################################################################################ + # close the websocket connections + ################################################################################################################ + await websocket.send_msg_to_debugger_server(main_thread_instance_id, main_thread_to_send_queue, 'close') + await websocket.send_msg_to_connect_server('close') + ################################################################################################################ \ No newline at end of file diff --git a/test/resource/tooling/ohos_test.xml b/test/resource/tooling/ohos_test.xml index a733d13e32a5499b4157a90a530a424e0d399741..5b9dc623bc688c595e4b79096efbd3052be9a5a5 100755 --- a/test/resource/tooling/ohos_test.xml +++ b/test/resource/tooling/ohos_test.xml @@ -275,4 +275,9 @@