From 15aa07f0fe8ddcded101bf828dcf1120953cb1da Mon Sep 17 00:00:00 2001 From: TaowerfulMAX Date: Mon, 27 Jan 2025 10:07:24 +0800 Subject: [PATCH] feat: hdc test scripts add module test. Signed-off-by: TaowerfulMAX --- scripts/hdc_medium_test.py | 156 -- scripts/hdc_normal_test.py | 864 ------- test/scripts/main.py | 57 + test/scripts/prepare.py | 142 ++ test/scripts/pytest.ini | 21 + test/scripts/readme.md | 119 + test/scripts/requirements.txt | 10 + test/scripts/testModule/test_hdc_base.py | 107 + test/scripts/testModule/test_hdc_file.py | 333 +++ test/scripts/testModule/test_hdc_fport.py | 87 + test/scripts/testModule/test_hdc_help.py | 23 + test/scripts/testModule/test_hdc_install.py | 103 + .../testModule/test_hdc_performance.py | 50 + test/scripts/testModule/test_hdc_server.py | 40 + test/scripts/testModule/test_hdc_shell.py | 89 + test/scripts/testModule/test_hdc_smode.py | 49 + test/scripts/testModule/test_hdc_tcp.py | 40 + test/scripts/testModule/test_hdc_tmode.py | 87 + test/scripts/testModule/test_hdc_usb.py | 39 + .../scripts/testModule/utils.py | 2081 ++++++++--------- 20 files changed, 2400 insertions(+), 2097 deletions(-) delete mode 100644 scripts/hdc_medium_test.py delete mode 100755 scripts/hdc_normal_test.py create mode 100755 test/scripts/main.py create mode 100755 test/scripts/prepare.py create mode 100644 test/scripts/pytest.ini create mode 100644 test/scripts/readme.md create mode 100644 test/scripts/requirements.txt create mode 100644 test/scripts/testModule/test_hdc_base.py create mode 100644 test/scripts/testModule/test_hdc_file.py create mode 100644 test/scripts/testModule/test_hdc_fport.py create mode 100644 test/scripts/testModule/test_hdc_help.py create mode 100644 test/scripts/testModule/test_hdc_install.py create mode 100644 test/scripts/testModule/test_hdc_performance.py create mode 100644 test/scripts/testModule/test_hdc_server.py create mode 100644 test/scripts/testModule/test_hdc_shell.py create mode 100644 test/scripts/testModule/test_hdc_smode.py create mode 100644 test/scripts/testModule/test_hdc_tcp.py create mode 100644 test/scripts/testModule/test_hdc_tmode.py create mode 100644 test/scripts/testModule/test_hdc_usb.py rename scripts/dev_hdc_test.py => test/scripts/testModule/utils.py (77%) mode change 100755 => 100644 diff --git a/scripts/hdc_medium_test.py b/scripts/hdc_medium_test.py deleted file mode 100644 index f450152b..00000000 --- a/scripts/hdc_medium_test.py +++ /dev/null @@ -1,156 +0,0 @@ -#!/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. -# 运行环境: python 3.10+, pytest, pytest-repeat, pytest-testreport -# 准备文件:package.zip -# pip install pytest pytest-testreport pytest-repeat -# python hdc_normal_test.py - - -import argparse -import logging -import os -import time -import pytest - - -from dev_hdc_test import GP -from dev_hdc_test import check_library_installation -from dev_hdc_test import check_hdc_cmd, check_hdc_targets, get_local_path, get_remote_path -from dev_hdc_test import check_soft_local, check_soft_remote -from dev_hdc_test import check_app_uninstall, prepare_source, make_multiprocess_file -from dev_hdc_test import execute_lines_in_file, hdc_get_key, rmdir, pytest_run - - -logging.basicConfig(level=logging.INFO, - format='%(asctime)s %(filename)s [line:%(lineno)d] %(levelname)s %(message)s', - datefmt='%d %b %Y %H:%M:%S', - ) - - -def test_list_targets(): - assert check_hdc_targets() - - -@pytest.mark.repeat(5) -def test_soft_link(): - assert check_soft_local(get_local_path('small'), - get_local_path('soft_small'), - get_remote_path('it_small_soft') - ) - assert check_soft_remote('it_small_soft', - get_remote_path('it_soft_small'), - get_local_path('recv_soft_small') - ) - - -@pytest.mark.repeat(1) -def test_mix_file(): - muti_num = 5 # the count of multiprocess file - assert make_multiprocess_file(get_local_path('small'), get_remote_path('it_small'), 'send', muti_num, "file") - assert make_multiprocess_file(get_local_path('small_recv'), get_remote_path('it_small'), 'recv', muti_num, "file") - assert make_multiprocess_file(get_local_path('medium'), get_remote_path('it_medium'), 'send', muti_num, "file") - assert make_multiprocess_file(get_local_path('medium_recv'), get_remote_path('it_medium'), 'recv', muti_num, "file") - - - -def test_recv_dir(): - assert make_multiprocess_file(get_local_path('package'), get_remote_path(''), 'send', 1, "dir") - assert check_hdc_cmd(f"shell mv {get_remote_path('package')} {get_remote_path('it_package')}") - assert make_multiprocess_file(get_local_path(''), get_remote_path('it_package'), 'recv', 1, "dir") - if os.path.exists(get_local_path('it_package')): - rmdir(get_local_path('it_package')) - - -def test_te_case(): - execute_lines_in_file('te.txt') - - -def test_hap_install(): - assert check_hdc_cmd(f"install -s {get_local_path('libA_v10001.hsp')}", - bundle="com.example.liba") - - assert check_hdc_cmd(f"install -s {get_local_path('libB_v10001.hsp')}", - bundle="com.example.libb") - - app_name_default_a = "com.example.liba" - app_name_default_b = "com.example.libb" - assert check_app_uninstall(app_name_default_a, "-s") - assert check_app_uninstall(app_name_default_b, "-s") - - -def test_shell_print(): - check_hdc_cmd("shell echo 'hello world'") - - -def test_shell_rm(): - check_hdc_cmd("shell rm -rf data/local/tmp/it_*") - - -def test_shell_ls(): - check_hdc_cmd("shell ls data/local/tmp") - - -def test_file_smap(): - pid = hdc_get_key("shell pidof hdcd") - check_hdc_cmd(f"file recv proc/{pid}/smaps resource/smaps") - - -def test_shell_mkdir(): - check_hdc_cmd("shell mkdir -p data/local/tmp/it") - - -def test_shell_rmdir(): - check_hdc_cmd("shell rmdir data/local/tmp/it") - - -def setup_class(): - print("setting up env ...") - check_hdc_cmd("shell rm -rf data/local/tmp/it_*") - GP.load() - - -def teardown_class(): - pass - - -def run_main(): - if check_library_installation("pytest"): - exit(1) - - if check_library_installation("pytest-testreport"): - exit(1) - - if check_library_installation("pytest-repeat"): - exit(1) - - GP.init() - if not os.path.exists(GP.local_path): - prepare_source() - - choice_default = "" - parser = argparse.ArgumentParser() - parser.add_argument('--count', type=int, default=1, - help='test times') - parser.add_argument('--verbose', '-v', default=__file__, - help='filename') - parser.add_argument('--desc', '-d', default='Test for function.', - help='Add description on report') - args = parser.parse_args() - - pytest_run(args) - - -if __name__ == "__main__": - run_main() \ No newline at end of file diff --git a/scripts/hdc_normal_test.py b/scripts/hdc_normal_test.py deleted file mode 100755 index 82e3828d..00000000 --- a/scripts/hdc_normal_test.py +++ /dev/null @@ -1,864 +0,0 @@ -#!/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. -# 运行环境: python 3.10+, pytest, pytest-repeat, pytest-testreport -# 准备文件:package.zip -# pip install pytest pytest-testreport pytest-repeat -# python hdc_normal_test.py - - -import argparse -import time -import os -import multiprocessing - -import pytest - -from dev_hdc_test import GP -from dev_hdc_test import check_library_installation, check_hdc_version, check_cmd_time -from dev_hdc_test import check_hdc_cmd, check_hdc_targets, get_local_path, get_remote_path, run_command_with_timeout -from dev_hdc_test import check_app_install, check_app_uninstall, prepare_source, pytest_run, update_source, check_rate -from dev_hdc_test import make_multiprocess_file, rmdir, get_shell_result -from dev_hdc_test import check_app_install_multi, check_app_uninstall_multi -from dev_hdc_test import check_rom, check_shell, check_shell_any_device, check_cmd_block - - -def test_hdc_server_foreground(): - port = os.getenv('OHOS_HDC_SERVER_PORT') - if port is None: - port = 8710 - assert check_hdc_cmd("kill", "Kill server finish") - assert check_cmd_block(f"{GP.hdc_exe} -m", f"port: {port}", timeout=5) - assert check_hdc_cmd("start") - time.sleep(3) # sleep 3s to wait for the device to connect channel - - -def test_list_targets(): - assert check_hdc_targets() - assert check_hdc_cmd("shell rm -rf data/local/tmp/it_*") - assert check_hdc_cmd("shell mkdir data/local/tmp/it_send_dir") - - -def test_usb_disconnect(): - assert check_hdc_targets() - cmd = 'shell "kill -9 `pidof hdcd`"' - check_hdc_cmd(f"{cmd}", "[Fail][E001003] USB communication abnormal, please check the USB communication link.") - time.sleep(2) - assert check_hdc_targets() - - -def test_list_targets_multi_usb_device(): - devices_str = check_shell_any_device(f"{GP.hdc_exe} list targets", None, True) - time.sleep(3) # sleep 3s to wait for the device to connect channel - devices_array = devices_str[1].split('\n') - if devices_array: - for device in devices_array: - if len(device) > 8: - assert check_shell_any_device(f"{GP.hdc_exe} -t {device} shell id", "u:r:")[0] - - -@pytest.mark.repeat(5) -def test_empty_file(): - assert check_hdc_cmd(f"file send {get_local_path('empty')} {get_remote_path('it_empty')}") - assert check_hdc_cmd(f"file recv {get_remote_path('it_empty')} {get_local_path('empty_recv')}") - - -@pytest.mark.repeat(5) -def test_empty_dir(): - assert check_shell(f"file send {get_local_path('empty_dir')} {get_remote_path('it_empty_dir')}", - "the source folder is empty") - assert check_hdc_cmd("shell mkdir data/local/tmp/it_empty_dir_recv") - assert check_shell(f"file recv {get_remote_path('it_empty_dir_recv')} {get_local_path('empty_dir_recv')}", - "the source folder is empty") - - -@pytest.mark.repeat(5) -def test_long_path(): - assert check_hdc_cmd(f"file send {get_local_path('deep_test_dir')} {get_remote_path('it_send_dir')}", - is_single_dir=False) - assert check_hdc_cmd(f"file recv {get_remote_path('it_send_dir/deep_test_dir')} {get_local_path('recv_test_dir')}", - is_single_dir=False) - - -@pytest.mark.repeat(3) -def test_no_exist_path(): - test_resource_list = ['empty', 'medium', 'small', 'problem_dir'] - remote_unexist_path = f"{get_remote_path('it_no_exist/deep_test_dir/')}" - for test_item in test_resource_list: - check_hdc_cmd(f"shell rm -rf {get_remote_path('it_no_exist*')}") - local_unexist_path = get_local_path(f'{(os.path.join("recv_no_exist", "deep_test_dir", f"recv_{test_item}"))}') - if os.path.exists(get_local_path('recv_no_exist')): - rmdir(get_local_path('recv_no_exist')) - assert check_hdc_cmd(f"file send " - f"{get_local_path(f'{test_item}')} {remote_unexist_path}/it_{test_item}") - assert check_hdc_cmd(f"file recv {remote_unexist_path}/it_{test_item} " - f"{local_unexist_path}") - - -@pytest.mark.repeat(3) -def test_no_exist_path_with_seperate(): - test_resource_list = ['empty', 'medium', 'small'] - remote_unexist_path = f"{get_remote_path('it_no_exist/deep_test_dir/')}" - for test_item in test_resource_list: - check_hdc_cmd(f"shell rm -rf {get_remote_path('it_no_exist*')}") - local_unexist_path = get_local_path(f'{(os.path.join("recv_no_exist", "deep_test_dir"))}') - if os.path.exists(get_local_path('recv_no_exist')): - rmdir(get_local_path('recv_no_exist')) - assert check_hdc_cmd(f"file send " - f"{get_local_path(f'{test_item}')} {remote_unexist_path}/") - assert check_hdc_cmd(f"file recv {remote_unexist_path}/{test_item} " - f"{local_unexist_path}{os.sep}") - - -@pytest.mark.repeat(3) -def test_no_exist_bundle_path(): - # bundle test - version = "Ver: 3.1.0e" - if not check_hdc_version("version", version) or not check_hdc_version("shell hdcd -v", version): - print("version does not match, ignore this case") - else: - data_storage_el2_path = "data/storage/el2/base" - remote_unexist_path = f"{data_storage_el2_path}/it_no_exist/deep_test_dir/" - check_shell(f"shell mkdir -p mnt/debug/100/debug_hap/{GP.debug_app}/{data_storage_el2_path}") - # file send & recv test - test_resource_list = ['empty', 'medium', 'small', 'problem_dir'] - for test_item in test_resource_list: - check_hdc_cmd(f"shell -b {GP.debug_app} rm -rf {data_storage_el2_path}/it_no_exist/") - local_unexist_path = get_local_path( - f'{(os.path.join("recv_no_exist", "deep_test_dir", f"recv_{test_item}"))}') - if os.path.exists(get_local_path('recv_no_exist')): - rmdir(get_local_path('recv_no_exist')) - - assert check_hdc_cmd(f"shell -b {GP.debug_app} ls {data_storage_el2_path}/it_no_exist", - "No such file or directory") - assert not os.path.exists(get_local_path('recv_no_exist')) - - assert check_hdc_cmd(f"file send -b {GP.debug_app} " - f"{get_local_path(f'{test_item}')} {remote_unexist_path}/it_{test_item}") - assert check_hdc_cmd(f"file recv -b {GP.debug_app} {remote_unexist_path}/it_{test_item} " - f"{local_unexist_path}") - - -@pytest.mark.repeat(5) -def test_small_file(): - assert check_hdc_cmd(f"file send {get_local_path('small')} {get_remote_path('it_small')}") - assert check_hdc_cmd(f"file recv {get_remote_path('it_small')} {get_local_path('small_recv')}") - - -@pytest.mark.repeat(5) -def test_small_file_compress(): - assert check_hdc_cmd(f"file send -z {get_local_path('small')} {get_remote_path('it_small_z')}") - assert check_hdc_cmd(f"file recv -z {get_remote_path('it_small_z')} {get_local_path('small_z_recv')}") - - -@pytest.mark.repeat(1) -def test_node_file(): - assert check_hdc_cmd(f"file recv {get_remote_path('../../../sys/power/state')} {get_local_path('state')}") - assert check_hdc_cmd(f"file recv {get_remote_path('../../../sys/firmware/fdt')} {get_local_path('fdt')}") - - -@pytest.mark.repeat(1) -def test_medium_file(): - assert check_hdc_cmd(f"file send {get_local_path('medium')} {get_remote_path('it_medium')}") - assert check_hdc_cmd(f"file recv {get_remote_path('it_medium')} {get_local_path('medium_recv')}") - - -@pytest.mark.repeat(1) -def test_medium_file_compress(): - assert check_hdc_cmd(f"file send -z {get_local_path('medium')} {get_remote_path('it_medium_z')}") - assert check_hdc_cmd(f"file recv -z {get_remote_path('it_medium_z')} {get_local_path('medium_z_recv')}") - - -@pytest.mark.repeat(1) -def test_medium_file_compress2(): - assert check_hdc_cmd(f"file send -z {get_local_path('word_100M.txt')} {get_remote_path('word_100M_compress.txt')}") - assert check_hdc_cmd(f"file recv -z {get_remote_path('word_100M_compress.txt')} {get_local_path('word_100M_compress_recv.txt')}") - - -@pytest.mark.repeat(1) -def test_large_file(): - assert check_hdc_cmd(f"file send {get_local_path('large')} {get_remote_path('it_large')}") - assert check_hdc_cmd(f"file recv {get_remote_path('it_large')} {get_local_path('large_recv')}") - - -@pytest.mark.repeat(1) -def test_large_file_compress(): - assert check_hdc_cmd(f"file send -z {get_local_path('large')} {get_remote_path('it_large_z')}") - assert check_hdc_cmd(f"file recv -z {get_remote_path('it_large_z')} {get_local_path('large_z_recv')}") - - -@pytest.mark.repeat(1) -def test_running_file(): - assert check_hdc_cmd(f"file recv system/bin/hdcd {get_local_path('running_recv')}") - - -@pytest.mark.repeat(1) -def test_rate(): - assert check_rate(f"file send {get_local_path('large')} {get_remote_path('it_large')}", 18000) - assert check_rate(f"file recv {get_remote_path('it_large')} {get_local_path('large_recv')}", 18000) - - -@pytest.mark.repeat(1) -def test_file_error(): - assert check_hdc_cmd("target mount") - assert check_shell( - f"file send {get_local_path('small')} system/bin/hdcd", - "busy" - ) - assert check_shell( - f"file recv", - "[Fail]There is no local and remote path" - ) - assert check_shell( - f"file send", - "[Fail]There is no local and remote path" - ) - assert check_hdc_cmd(f"shell rm -rf {get_remote_path('../../../large')}") - assert check_hdc_cmd(f"shell param set persist.hdc.control.file false") - assert check_shell( - f"file send {get_local_path('small')} {get_remote_path('it_small_false')}", - "debugging is not allowed" - ) - assert check_hdc_cmd(f"shell param set persist.hdc.control.file true") - assert check_hdc_cmd(f"file send {get_local_path('small')} {get_remote_path('it_small_true')}") - - -@pytest.mark.repeat(5) -def test_recv_dir(): - if os.path.exists(get_local_path('it_problem_dir')): - rmdir(get_local_path('it_problem_dir')) - assert check_hdc_cmd(f"shell rm -rf {get_remote_path('it_problem_dir')}") - assert check_hdc_cmd(f"shell rm -rf {get_remote_path('problem_dir')}") - assert make_multiprocess_file(get_local_path('problem_dir'), get_remote_path(''), 'send', 1, "dir") - assert check_hdc_cmd(f"shell mv {get_remote_path('problem_dir')} {get_remote_path('it_problem_dir')}") - assert make_multiprocess_file(get_local_path(''), get_remote_path('it_problem_dir'), 'recv', 1, "dir") - - -@pytest.mark.repeat(5) -def test_hap_install(): - assert check_hdc_cmd(f"install -r {get_local_path('entry-default-signed-debug.hap')}", - bundle="com.hmos.diagnosis") - - -@pytest.mark.repeat(5) -def test_install_hap(): - package_hap = "entry-default-signed-debug.hap" - app_name_default = "com.hmos.diagnosis" - - # default - assert check_app_install(package_hap, app_name_default) - assert check_app_uninstall(app_name_default) - - # -r - assert check_app_install(package_hap, app_name_default, "-r") - assert check_app_uninstall(app_name_default) - - # -k - assert check_app_install(package_hap, app_name_default, "-r") - assert check_app_uninstall(app_name_default, "-k") - - # -s - assert check_app_install(package_hap, app_name_default, "-s") - - -@pytest.mark.repeat(5) -def test_install_hsp(): - package_hsp = "libA_v10001.hsp" - hsp_name_default = "com.example.liba" - - assert check_app_install(package_hsp, hsp_name_default, "-s") - assert check_app_uninstall(hsp_name_default, "-s") - assert check_app_install(package_hsp, hsp_name_default) - - -@pytest.mark.repeat(5) -def test_install_multi_hap(): - # default multi hap - tables = { - "entry-default-signed-debug.hap" : "com.hmos.diagnosis", - "ActsAudioRecorderJsTest.hap" : "ohos.acts.multimedia.audio.audiorecorder" - } - assert check_app_install_multi(tables) - assert check_app_uninstall_multi(tables) - assert check_app_install_multi(tables, "-s") - - # default multi hap -r -k - tables = { - "entry-default-signed-debug.hap" : "com.hmos.diagnosis", - "ActsAudioRecorderJsTest.hap" : "ohos.acts.multimedia.audio.audiorecorder" - } - assert check_app_install_multi(tables, "-r") - assert check_app_uninstall_multi(tables, "-k") - - -@pytest.mark.repeat(5) -def test_install_multi_hsp(): - # default multi hsp -s - tables = { - "libA_v10001.hsp" : "com.example.liba", - "libB_v10001.hsp" : "com.example.libb", - } - assert check_app_install_multi(tables, "-s") - assert check_app_uninstall_multi(tables, "-s") - assert check_app_install_multi(tables) - - -@pytest.mark.repeat(5) -def test_install_hsp_and_hap(): - #default multi hsp and hsp - tables = { - "libA_v10001.hsp" : "com.example.liba", - "entry-default-signed-debug.hap" : "com.hmos.diagnosis", - } - assert check_app_install_multi(tables) - assert check_app_install_multi(tables, "-s") - - -@pytest.mark.repeat(5) -def test_install_dir(): - package_haps_dir = "app_dir" - app_name_default = "com.hmos.diagnosis" - assert check_app_install(package_haps_dir, app_name_default) - assert check_app_uninstall(app_name_default) - - -def test_server_kill(): - assert check_hdc_cmd("kill", "Kill server finish") - assert check_hdc_cmd("start server") - time.sleep(3) # sleep 3s to wait for the device to connect channel - assert check_hdc_cmd("kill -r", "Start server finish") - assert check_hdc_cmd("start -r", "hdc start server") - assert check_hdc_cmd("checkserver", "Ver") - - -def test_target_cmd(): - assert check_hdc_targets() - check_hdc_cmd("target boot") - start_time = time.time() - run_command_with_timeout(f"{GP.hdc_head} wait", 30) # reboot takes up to 30 seconds - time.sleep(3) # sleep 3s to wait for the device to boot - run_command_with_timeout(f"{GP.hdc_head} wait", 30) # reboot takes up to 30 seconds - end_time = time.time() - print(f"command exec time {end_time - start_time}") - time.sleep(3) # sleep 3s to wait for the device to connect channel - assert (end_time - start_time) > 8 # Reboot takes at least 8 seconds - - -@pytest.mark.repeat(1) -def test_file_switch_off(): - assert check_hdc_cmd("shell param set persist.hdc.control.file false") - assert check_shell(f"shell param get persist.hdc.control.file", "false") - assert check_shell(f"file send {get_local_path('small')} {get_remote_path('it_small')}", - "debugging is not allowed") - assert check_shell(f"file recv {get_remote_path('it_small')} {get_local_path('small_recv')}", - "debugging is not allowed") - - -@pytest.mark.repeat(1) -def test_file_switch_on(): - assert check_hdc_cmd("shell param set persist.hdc.control.file true") - assert check_shell(f"shell param get persist.hdc.control.file", "true") - assert check_hdc_cmd(f"file send {get_local_path('small')} {get_remote_path('it_small')}") - assert check_hdc_cmd(f"file recv {get_remote_path('it_small')} {get_local_path('small_recv')}") - - -def test_target_mount(): - assert (check_hdc_cmd("target mount", "Mount finish" or "[Fail]Operate need running as root")) - remount_vendor = get_shell_result(f'shell "mount |grep /vendor |head -1"') - print(remount_vendor) - assert "rw" in remount_vendor - remount_system = get_shell_result(f'shell "cat proc/mounts | grep /system |head -1"') - print(remount_system) - assert "rw" in remount_system - - -def test_tmode_port(): - assert (check_hdc_cmd("tmode port", "Set device run mode successful")) - time.sleep(3) # sleep 3s to wait for the device to connect channel - run_command_with_timeout(f"{GP.hdc_head} wait", 3) # wait 3s for the device to connect channel - time.sleep(3) # sleep 3s to wait for the device to connect channel - run_command_with_timeout(f"{GP.hdc_head} wait", 3) # wait 3s for the device to connect channel - assert (check_hdc_cmd("tmode port 12345")) - time.sleep(3) # sleep 3s to wait for the device to connect channel - run_command_with_timeout(f"{GP.hdc_head} wait", 3) # wait 3s for the device to connect channel - time.sleep(3) # sleep 3s to wait for the device to connect channel - run_command_with_timeout(f"{GP.hdc_head} wait", 3) # wait 3s for the device to connect channel - netstat_port = get_shell_result(f'shell "netstat -anp | grep 12345"') - print(netstat_port) - assert "LISTEN" in netstat_port - assert "hdcd" in netstat_port - - -def test_tconn(): - daemon_port = 58710 - address = "127.0.0.1" - assert (check_hdc_cmd(f"tmode port {daemon_port}")) - time.sleep(3) # sleep 3s to wait for the device to connect channel - run_command_with_timeout(f"{GP.hdc_head} wait", 3) # wait 3s for the device to connect channel - time.sleep(3) # sleep 3s to wait for the device to connect channel - run_command_with_timeout(f"{GP.hdc_head} wait", 3) # wait 3s for the device to connect channel - assert check_hdc_cmd(f"shell param get persist.hdc.port", f"{daemon_port}") - assert check_hdc_cmd(f"fport tcp:{daemon_port} tcp:{daemon_port}", "Forwardport result:OK") - assert check_hdc_cmd(f"fport ls ", f"tcp:{daemon_port} tcp:{daemon_port}") - assert check_shell(f"tconn {address}:{daemon_port}", "Connect OK", head=GP.hdc_exe) - time.sleep(3) - assert check_shell("list targets", f"{address}:{daemon_port}", head=GP.hdc_exe) - tcp_head = f"{GP.hdc_exe} -t {address}:{daemon_port}" - assert check_hdc_cmd(f"file send {get_local_path('medium')} {get_remote_path('it_tcp_medium')}", - head=tcp_head) - assert check_hdc_cmd(f"file recv {get_remote_path('it_tcp_medium')} {get_local_path('medium_tcp_recv')}", - head=tcp_head) - assert check_shell(f"tconn {address}:{daemon_port} -remove", head=GP.hdc_exe) - assert not check_shell("list targets", f"{address}:{daemon_port}", head=GP.hdc_exe) - assert check_hdc_cmd(f"fport rm tcp:{daemon_port} tcp:{daemon_port}", "Remove forward ruler success") - assert not check_hdc_cmd(f"fport ls ", f"tcp:{daemon_port} tcp:{daemon_port}") - - -def test_target_key(): - device_key = get_shell_result(f"list targets").split("\r\n")[0] - hdcd_pid = get_shell_result(f"-t {device_key} shell pgrep -x hdcd").split("\r\n")[0] - assert hdcd_pid.isdigit() - - -def test_version_cmd(): - version = "Ver: 2.0.0a" - assert check_hdc_version("-v", version) - assert check_hdc_version("version", version) - assert check_hdc_version("checkserver", version) - - -def test_fport_cmd_output(): - local_port = 18070 - remote_port = 11080 - fport_arg = f"tcp:{local_port} tcp:{remote_port}" - assert check_hdc_cmd(f"fport {fport_arg}", "Forwardport result:OK") - assert check_shell_any_device(f"netstat -ano", "LISTENING", False)[0] - assert check_shell_any_device(f"netstat -ano", f"{local_port}", False)[0] - assert check_hdc_cmd(f"fport ls", fport_arg) - assert check_hdc_cmd(f"fport rm {fport_arg}", "success") - - -def test_rport_cmd_output(): - local_port = 17090 - remote_port = 11080 - rport_arg = f"tcp:{local_port} tcp:{remote_port}" - assert check_hdc_cmd(f"rport {rport_arg}", "Forwardport result:OK") - netstat_line = get_shell_result(f'shell "netstat -anp | grep {local_port}"') - assert "LISTEN" in netstat_line - assert "hdcd" in netstat_line - fport_list = get_shell_result(f"fport ls") - assert "Reverse" in fport_list - assert rport_arg in fport_list - assert check_hdc_cmd(f"fport rm {rport_arg}", "success") - - -def test_fport_cmd(): - fport_list = [] - rport_list = [] - start_port = 10000 - end_port = 10020 - for i in range(start_port, end_port): - fport = f"tcp:{i+100} tcp:{i+200}" - rport = f"tcp:{i+300} tcp:{i+400}" - localabs = f"tcp:{i+500} localabstract:{f'helloworld.com.app.{i+600}'}" - fport_list.append(fport) - rport_list.append(rport) - fport_list.append(localabs) - - for fport in fport_list: - assert check_hdc_cmd(f"fport {fport}", "Forwardport result:OK") - assert check_hdc_cmd(f"fport {fport}", "TCP Port listen failed at") - assert check_hdc_cmd("fport ls", fport) - - for fport in fport_list: - assert check_hdc_cmd(f"fport rm {fport}", "success") - assert not check_hdc_cmd("fport ls", fport) - - for rport in rport_list: - assert check_hdc_cmd(f"rport {rport}", "Forwardport result:OK") - assert check_hdc_cmd(f"rport {rport}", "TCP Port listen failed at") - assert check_hdc_cmd("rport ls", rport) or check_hdc_cmd("fport ls", rport) - - for rport in rport_list: - assert check_hdc_cmd(f"fport rm {rport}", "success") - assert not check_hdc_cmd("rport ls", fport) and not check_hdc_cmd("fport ls", fport) - - task_str1 = "tcp:33333 tcp:33333" - assert check_hdc_cmd(f"fport {task_str1}", "Forwardport result:OK") - assert check_hdc_cmd(f"fport rm {task_str1}", "success") - assert check_hdc_cmd(f"fport {task_str1}", "Forwardport result:OK") - assert check_hdc_cmd(f"fport rm {task_str1}", "success") - - task_str2 = "tcp:44444 tcp:44444" - assert check_hdc_cmd(f"rport {task_str2}", "Forwardport result:OK") - assert check_hdc_cmd(f"fport rm {task_str2}", "success") - assert check_hdc_cmd(f"rport {task_str2}", "Forwardport result:OK") - assert check_hdc_cmd(f"fport rm {task_str2}", "success") - - -#子进程执行函数 -def new_process_run(cmd): - # 重定向 stdout 和 stderr 到 /dev/null - with open(os.devnull, 'w') as devnull: - old_stdout = os.dup2(devnull.fileno(), 1) # 重定向 stdout - old_stderr = os.dup2(devnull.fileno(), 2) # 重定向 stderr - try: - # 这里是子进程的代码,不会有任何输出到控制台 - check_shell(f'{cmd}') - finally: - # 恢复原始的 stdout 和 stderr - os.dup2(old_stdout, 1) - os.dup2(old_stderr, 2) - - -def test_hilog_exit_after_hdc_kill(): - # 新开进程执行hdc shell hilog,防止阻塞主进程 - p = multiprocessing.Process(target=new_process_run, args=("shell hilog",)) - p.start() - time.sleep(1) - hilog_pid = get_shell_result(f'shell pidof hilog') - hilog_pid = hilog_pid.replace("\r\n", "") - assert hilog_pid.isdigit() - assert check_hdc_cmd(f'kill', "Kill server finish") - assert check_hdc_cmd("start") - time.sleep(3) # sleep 3s to wait for the device to connect channel - run_command_with_timeout(f"{GP.hdc_head} wait", 3) # wait 3s for the device to connect channel - hilog_pid2 = get_shell_result(f'shell pidof hilog') - assert hilog_pid2 == '' - p.join() - - -def test_shell_cmd_timecost(): - assert check_cmd_time( - cmd="shell \"ps -ef | grep hdcd\"", - pattern="hdcd", - duration=None, - times=10) - - -def test_shell_huge_cat(): - assert check_hdc_cmd(f"file send {get_local_path('word_100M.txt')} {get_remote_path('it_word_100M.txt')}") - assert check_cmd_time( - cmd=f"shell cat {get_remote_path('it_word_100M.txt')}", - pattern=None, - duration=10000, # 10 seconds - times=10) - - -def test_file_option_bundle_normal(): - version = "Ver: 3.1.0e" - if not check_hdc_version("version", version) or not check_hdc_version("shell hdcd -v", version): - print("version does not match, ignore this case") - else: - data_storage_el2_path = "data/storage/el2/base" - check_shell(f"shell rm -rf mnt/debug/100/debug_hap/{GP.debug_app}/{data_storage_el2_path}/it*") - check_shell(f"shell mkdir -p mnt/debug/100/debug_hap/{GP.debug_app}/{data_storage_el2_path}") - - # file send & recv test - test_resource_list = ['empty', 'medium', 'small', 'problem_dir'] - for test_item in test_resource_list: - if test_item == 'problem_dir' and os.path.exists(get_local_path(f'recv_bundle_{test_item}')): - rmdir(get_local_path(f'recv_bundle_{test_item}')) - - assert check_hdc_cmd(f"file send -b {GP.debug_app} " - f"{get_local_path(f'{test_item}')} {data_storage_el2_path}/it_{test_item}") - assert check_hdc_cmd(f"file recv -b {GP.debug_app} {data_storage_el2_path}/it_{test_item} " - f"{get_local_path(f'recv_bundle_{test_item}')} ") - - -def test_file_option_bundle_error(): - version = "Ver: 3.1.0e" - if not check_hdc_version("version", version) or not check_hdc_version("shell hdcd -v", version): - print("version does not match, ignore this case") - else: - data_storage_el2_path = "data/storage/el2/base" - is_user = check_shell("shell id", "uid=2000(shell)") - assert check_shell(f"file send -b {GP.debug_app} " - f"{get_local_path('empty_dir')} {get_remote_path('it_empty_dir')}", - "the source folder is empty") - - assert check_shell(f"file send -b {GP.debug_app} ", "There is no local and remote path") - assert check_shell(f"file recv -b {GP.debug_app} ", "There is no local and remote path") - - # 报错优先级 - assert check_shell(f"file send -b ./{GP.debug_app} ", "There is no local and remote path") - assert check_shell(f"file recv -b ./{GP.debug_app} ", "There is no local and remote path") - - # 报错优先级 - assert check_shell(f"file recv -b ", "[E005003]") - assert check_shell(f"file send -b ", "[E005003]") - - assert check_shell(f"file send -b ./{GP.debug_app} " - f"{get_local_path('small')} {get_remote_path('it_small')}", "[E005101]") - assert check_shell(f"file recv -b ./{GP.debug_app} " - f"{get_local_path('small')} {get_remote_path('it_small')}", "[E005101]") - - # bundle不存在或不符合要求 - assert check_shell(f"file send -b ./{GP.debug_app} " - f"{get_local_path('small')} {get_remote_path('it_small')}", "[E005101]") - assert check_shell(f"file send -b com.AAAA " - f"{get_local_path('small')} {get_remote_path('it_small')}", "[E005101]") - assert check_shell(f"file send -b 1 " - f"{get_local_path('small')} {get_remote_path('it_small')}", "[E005101]") - assert check_shell(f"file send -b " - f"{get_local_path('small')} {get_remote_path('it_small')}", "There is no remote path") - assert check_shell(f"file recv -b ./{GP.debug_app} " - f"{get_remote_path('it_small')} {get_local_path('small_recv')}", "[E005101]") - # 逃逸 - assert check_shell(f"file send -b {GP.debug_app} " - f"{get_local_path('small')} ../../../it_small", "[E005102]") - assert check_shell(f"file recv -b {GP.debug_app} ../../../it_small" - f"{get_local_path('small_recv')} ", "[E005102]") - assert check_shell(f"file send -b {GP.debug_app} " - f"{get_local_path('small')} {data_storage_el2_path}/../../../../../ ", - "permission denied" if is_user else "[E005102]") - - -def test_file_option_bundle_error_bugfix(): - version = "Ver: 3.1.0e" - if not check_hdc_version("version", version) or not check_hdc_version("shell hdcd -v", version): - print("version does not match, ignore this case") - else: - data_storage_el2_path = "data/storage/el2/base" - check_shell(f"shell rm -rf mnt/debug/100/debug_hap/{GP.debug_app}_extra/{data_storage_el2_path}/*") - check_shell(f"shell mkdir -p mnt/debug/100/debug_hap/{GP.debug_app}_extra/{data_storage_el2_path}/") - outside_error = "[E005102]" - # bundle根目录 逃逸 - for remote_fail_path in ["..", "../..", "../../..", "../../../..", - "../.", "./..", "../", - f"../{GP.debug_app}_extra/{data_storage_el2_path}/", - f"../{GP.debug_app}_notexsit/{data_storage_el2_path}/", - f"../{GP.debug_app}_notexsit/", - f"./../../../../../../../../../../aa"]: - assert check_shell(f"file send -b {GP.debug_app} " - f"{get_local_path('small')} {remote_fail_path} ", outside_error) - - # bundle根目录 未逃逸 - for remote_ok_path in ['.', './', './.', '...', - f"../../../../../../../../../../../mnt/debug/100/debug_hap/{GP.debug_app}/"]: - assert not check_shell(f"file send -b {GP.debug_app} " - f"{get_local_path('small')} {remote_ok_path}", outside_error) - - -def test_shell_option_bundle_normal(): - version = "Ver: 3.1.0e" - if not check_hdc_version("version", version) or not check_hdc_version("shell hdcd -v", version): - print("version does not match, ignore this case") - else: - data_storage_el2_path = "data/storage/el2/base" - check_shell(f"shell mkdir -p mnt/debug/100/debug_hap/{GP.debug_app}/{data_storage_el2_path}") - assert check_shell(f"shell -b {GP.debug_app} pwd", f"mnt/debug/100/debug_hap/{GP.debug_app}") - assert check_shell(f"shell -b {GP.debug_app} cd {data_storage_el2_path}; pwd", - f"mnt/debug/100/debug_hap/{GP.debug_app}/{data_storage_el2_path}") - check_shell(f"shell -b {GP.debug_app} touch {data_storage_el2_path}/test01") - assert not check_shell(f"shell -b {GP.debug_app} touch {data_storage_el2_path}/test01", "denied") - assert not check_shell(f"shell -b {GP.debug_app} touch -a {data_storage_el2_path}/test01", "denied") - assert check_shell(f"shell -b {GP.debug_app} ls {data_storage_el2_path}/", "test01") - assert check_shell(f"shell -b {GP.debug_app} echo 123 ", - "123") - check_shell(f"shell -b {GP.debug_app} \"echo 123 > {data_storage_el2_path}/test02\"") - assert check_shell(f"shell -b {GP.debug_app} cat {data_storage_el2_path}/test02", "123") - check_shell(f"shell -b {GP.debug_app} mkdir {data_storage_el2_path}/test03") - assert check_shell(f"shell -b {GP.debug_app} stat {data_storage_el2_path}/test03", "Access") - check_shell(f"shell -b {GP.debug_app} rm -rf {data_storage_el2_path}/test01 " - f"{data_storage_el2_path}/test02 {data_storage_el2_path}/test03") - assert check_shell(f"shell -b {GP.debug_app} ls {data_storage_el2_path}/test01", - "test01: No such file or directory") - assert check_shell(f"shell -b {GP.debug_app} ls {data_storage_el2_path}/test02", - "test02: No such file or directory") - assert check_shell(f"shell -b {GP.debug_app} ls {data_storage_el2_path}/test03", - "test03: No such file or directory") - - -def test_shell_option_bundle_error(): - version = "Ver: 3.1.0e" - if not check_hdc_version("version", version) or not check_hdc_version("shell hdcd -v", version): - print("version does not match, ignore this case") - else: - # 不存在的bundle名称 - assert check_shell("shell -b com.XXXX.not.exist.app pwd", "[Fail][E003001]") - # 相对路径逃逸1 - assert check_shell(f"shell -b ../../../../ pwd", "[Fail][E003001") - # 相对路径逃逸2 - assert check_shell(f"shell -b ././././pwd", "[Fail][E003001]") - # 相对路径逃逸3 - assert check_shell(f"shell -b / pwd", "[Fail][E003001]") - # 交互式shell不支持 - assert check_shell(f"shell -b {GP.debug_app}", "[Fail][E003002]") - # bundle参数(129)超过128 - str_len_129 = "a" * 129 - assert check_shell(f"shell -b {str_len_129} pwd", "[Fail][E003001]") - # bundle参数(6)低于7 - str_len_6 = "a" * 6 - assert check_shell(f"shell -b {str_len_6} pwd", "[Fail][E003001]") - # bundle参数存在非法参数 - str_invalid = "#########" - assert check_shell(f"shell -b {str_invalid} pwd", "[Fail][E003001]") - # 其他参数用例1 - assert check_shell("shell -param 1234567890 pwd", "[Fail][E003003]") - # 其他参数用例2 - assert check_shell("shell -basd {GP.debug_app} pwd", "[Fail][E003003]") - # 缺少参数字母 - assert check_shell(f"shell - {GP.debug_app} ls", "[Fail][E003003]") - # 缺少bundle参数1 - assert check_shell("shell -b ls", "[Fail][E003001]") - # 缺少bundle参数2 - assert check_shell("shell -b", "[Fail][E003005]") - # 存在未知参数在前面 - assert check_shell(f"shell -t -b {GP.debug_app} ls", "[Fail][E003003]") - # 参数在后面 - assert check_shell(f"shell ls -b {GP.debug_app}", "No such file or directory") - # 双倍参数 - assert check_shell(f"shell -b -b {GP.debug_app} ls", "[Fail][E003001]") - # 双倍-杠 - assert check_shell(f"shell --b {GP.debug_app}", "[Fail][E003003]") - - -def test_option_bundle_error_usage_support(): - version = "Ver: 3.1.0e" - if not check_hdc_version("version", version) or not check_hdc_version("shell hdcd -v", version): - print("version does not match, ignore this case") - else: - assert check_shell("shell -b", "Usage: hdc shell [-b bundlename] [COMMAND...]") - assert check_shell(f"file recv -b ", "Usage: hdc file recv [-b bundlename] remote local") - assert check_shell(f"file send -b ", "Usage: hdc file send [-b bundlename] local remote") - - -def test_hdcd_rom(): - baseline = 2200 # 2200KB - assert check_rom(baseline) - - -def test_smode_permission(): - check_shell(f"shell rm -rf data/deep_test_dir") - assert check_hdc_cmd(f'smode -r') - time.sleep(3) - run_command_with_timeout(f"{GP.hdc_head} wait", 3) # wait 3s for the device to connect channel - assert check_shell(f"file send {get_local_path('deep_test_dir')} data/", - "permission denied") - assert check_shell(f"file send {get_local_path('deep_test_dir')} data/", - "[E005005]") - - -def test_smode_r(): - assert check_hdc_cmd(f'smode -r') - time.sleep(3) # sleep 3s to wait for the device to connect channel - run_command_with_timeout(f"{GP.hdc_head} wait", 3) # wait 3s for the device to connect channel - time.sleep(3) # sleep 3s to wait for the device to connect channel - run_command_with_timeout(f"{GP.hdc_head} wait", 3) # wait 3s for the device to connect channel - assert check_shell(f"shell id", "context=u:r:sh:s0") - assert check_shell(f"file send {get_local_path('deep_test_dir')} data/", - "permission denied") - - -def test_smode(): - assert check_hdc_cmd(f'smode') - time.sleep(3) # sleep 3s to wait for the device to connect channel - run_command_with_timeout(f"{GP.hdc_head} wait", 3) # wait 3s for the device to connect channel - time.sleep(3) # sleep 3s to wait for the device to connect channel - run_command_with_timeout(f"{GP.hdc_head} wait", 3) # wait 3s for the device to connect channel - assert check_shell(f"shell id", "context=u:r:su:s0") - assert not check_hdc_cmd("ls /data/log/faultlog/faultlogger | grep hdcd", "hdcd") - - -def test_persist_hdc_mode_tcp(): - assert check_hdc_cmd(f"shell param set persist.hdc.mode.tcp enable") - time.sleep(5) - run_command_with_timeout("hdc wait", 3) - netstat_listen = get_shell_result(f'shell "netstat -anp | grep tcp | grep hdcd"') - assert "LISTEN" in netstat_listen - assert "hdcd" in netstat_listen - assert check_hdc_cmd(f"shell param set persist.hdc.mode.tcp enable") - time.sleep(5) - run_command_with_timeout("hdc wait", 3) - netstat_listen = get_shell_result(f'shell "netstat -anp | grep tcp | grep hdcd"') - assert "LISTEN" in netstat_listen - assert "hdcd" in netstat_listen - assert check_hdc_cmd(f"shell param set persist.hdc.mode.tcp disable") - time.sleep(5) - run_command_with_timeout("hdc wait", 3) - netstat_listen = get_shell_result(f'shell "netstat -anp | grep tcp | grep hdcd"') - assert "LISTEN" not in netstat_listen - assert "hdcd" not in netstat_listen - - -def test_persist_hdc_mode_usb(): - assert check_hdc_cmd(f"shell param set persist.hdc.mode.usb enable") - echo_result = get_shell_result(f'shell "echo 12345"') - assert "12345" not in echo_result - time.sleep(10) - run_command_with_timeout("hdc wait", 3) - echo_result = get_shell_result(f'shell "echo 12345"') - assert "12345" in echo_result - - -def test_persist_hdc_mode_tcp_usb(): - assert check_hdc_cmd(f"shell param set persist.hdc.mode.tcp enable") - time.sleep(5) - run_command_with_timeout("hdc wait", 3) - assert check_hdc_cmd(f"shell param set persist.hdc.mode.usb enable") - time.sleep(10) - run_command_with_timeout("hdc wait", 3) - netstat_listen = get_shell_result(f'shell "netstat -anp | grep tcp | grep hdcd"') - assert "LISTEN" in netstat_listen - assert "hdcd" in netstat_listen - assert check_hdc_cmd(f"shell param set persist.hdc.mode.tcp disable") - time.sleep(5) - run_command_with_timeout("hdc wait", 3) - netstat_listen = get_shell_result(f'shell "netstat -anp | grep tcp | grep hdcd"') - assert "LISTEN" not in netstat_listen - assert "hdcd" not in netstat_listen - - - -def setup_class(): - print("setting up env ...") - check_hdc_cmd("shell rm -rf data/local/tmp/it_*") - GP.load() - - -def teardown_class(): - pass - - -def run_main(): - if check_library_installation("pytest"): - exit(1) - - if check_library_installation("pytest-testreport"): - exit(1) - - if check_library_installation("pytest-repeat"): - exit(1) - - GP.init() - - prepare_source() - update_source() - - choice_default = "" - parser = argparse.ArgumentParser() - parser.add_argument('--count', type=int, default=1, - help='test times') - parser.add_argument('--verbose', '-v', default=__file__, - help='filename') - parser.add_argument('--desc', '-d', default='Test for function.', - help='Add description on report') - args = parser.parse_args() - - pytest_run(args) - - -if __name__ == "__main__": - run_main() diff --git a/test/scripts/main.py b/test/scripts/main.py new file mode 100755 index 00000000..1127a00a --- /dev/null +++ b/test/scripts/main.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. +# 运行环境: python 3.10+, pytest, pytest-repeat, pytest-testreport allure-pytest +# pytest-xdist, pytest-ordering, pytest-rerunfailures, setuptools, Jinja2, requests +# 准备文件:package.zip +# 执行方式:python main.py + +import subprocess +import pytest +import os +import time +import prepare +from testModule.utils import GP, check_library_installation, pytest_run, load_gp + + +def get_version_file(): + version_file_path = os.path.join(os.getcwd(), "resource", "version") + if os.path.exists(version_file_path): + with open(version_file_path, "r", encoding="UTF-8") as version_file: + version = version_file.read().strip() + return version + else: + return "unknown" + + +def is_gen_conf(): + config_file_path = os.path.join(os.getcwd(), ".hdctester.conf") + return os.path.exists(config_file_path) + + +def main(): + if check_library_installation("pytest"): + subprocess.check_call(["pip", "install", "-r", "requirements.txt"]) + if check_library_installation("pytest"): + return + start_time = time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(time.time())) + if get_version_file() == "unknown": + prepare.main() + if not is_gen_conf(): + GP.init() + pytest_run() + + +if __name__ == '__main__': + main() \ No newline at end of file diff --git a/test/scripts/prepare.py b/test/scripts/prepare.py new file mode 100755 index 00000000..f7c3220b --- /dev/null +++ b/test/scripts/prepare.py @@ -0,0 +1,142 @@ +#!/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. + +import subprocess +import zipfile +import hashlib +import os +from testModule.utils import GP, gen_package_dir, update_source, prepare_source + + +def install_dependencies(requirements_file): + try: + subprocess.check_call(["pip", "install", "-r", requirements_file]) + print(f"install requirements.txt success") + except subprocess.CalledProcessError as e: + print(f"install dependence fail: {str(e)}") + + +def check_exist_file(): + file_list = [] + file_list.append("AACommand07.hap") + file_list.append("libA_v10001.hsp") + file_list.append("libB_v10001.hsp") + url = "https://gitee.com/TaowerfulMAX/h2dij432sfa423o_debugfortest/releases/download/0.0.1-debug/package_0.0.1.zip" + expected_md5 = "ace0655b5f8dfb181544c92ae90f7bfc" + for file in file_list: + if not os.path.exists(os.path.join(GP.local_path, file)): + if download_and_extract_zip(url, os.path.join(GP.local_path), expected_md5): + print(f"{file} File Download Success") + continue + else: + print(f"{file} File Download Failed") + print(f"No {file} File!") + print(f"请自行访问以下链接,下载package.zip中的安装包文件解压到当前脚本resource目录中," + "操作完成该步骤后重新执行prepare.py脚本。") + print("Please download from the url below and unzip package.zip to resource directory," + "please rerun after operation.") + print("url: " + url) + exit(1) + + +def download_file(url, timeout=(10, 30)): + try: + import requests + except ModuleNotFoundError: + print("Please install requests module, command: [pip install requests]") + exit(1) + try: + response = requests.get(url, timeout=timeout) + response.raise_for_status() # 将触发HTTPError,如果状态不是200 + return True, response.content + except requests.exceptions.Timeout: + return False, "请求超时" + except requests.exceptions.HTTPError as err: + return False, f"HTTP错误:{err}" + except requests.exceptions.RequestException as e: + return False, f"请求异常:{e}" + + +def save_to_file(content, filename): + with open(filename, 'wb') as f: + f.write(content) + + +def extract_zip(filename, extract_to='.'): + with zipfile.ZipFile(filename, 'r') as zip_ref: + zip_ref.extractall(extract_to) + + +def calculate_md5(filename): + hash_md5 = hashlib.md5() + try: + with open(filename, 'rb') as f: + for chunk in iter(lambda: f.read(4096), b""): + hash_md5.update(chunk) + return hash_md5.hexdigest() + except PermissionError: + return "PermissionError" + except FileNotFoundError: + return "FileNotFoundError" + + +def download_and_extract_zip(url, extract_to='.', expected_md5=None): + # 下载ZIP文件 + is_success, content = download_file(url) + if not is_success: + print(f"download_file failed: {content}") + return False + # 获取ZIP文件名 + zip_filename = url.split('/')[-1] + + # 写入本地文件 + save_to_file(content, zip_filename) + + # 如果提供了预期的MD5值,则进行校验 + if expected_md5: + file_md5 = calculate_md5(zip_filename) + if file_md5 != expected_md5: + raise Exception(f"MD5校验失败:预期的MD5为{expected_md5},实际为{file_md5}") + else: + print("MD5校验成功") + + # 解压ZIP文件 + extract_zip(zip_filename, extract_to) + + # 可选:删除ZIP文件 + os.remove(zip_filename) + print(f"文件已解压到:{extract_to}") + return True + + +def prepare(): + prepare_source() + update_source() + check_exist_file() + gen_package_dir() + + +def main(): + install_dependencies("requirements.txt") + test_path = os.path.join(os.getcwd(), "testModule") + if not os.path.exists(test_path): + print("testModule not exist") + return + GP.init() + prepare() + + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/test/scripts/pytest.ini b/test/scripts/pytest.ini new file mode 100644 index 00000000..c6b11c3b --- /dev/null +++ b/test/scripts/pytest.ini @@ -0,0 +1,21 @@ +[pytest] +# 命令行规则,空格分隔 +# -m "L0 or L1" +# --alluredir ./temp +addopts = -v --report=report.html --title=测试报告 --tester=测试员 --desc=报告描述信息 --template=1 +# 测试用例路径 +testpaths = testModule +# 模块名的规则 +python_files = test*.py +# 类名的规则 +python_classes = Test* +# 方法名的规格 +python_functions = test* +# pytest执行顺序默认从上到下,需要改变顺序进行order参数控制 + +#用例分类,自定义标签 +markers = + L0:冒烟用例 + L1:基础用例 + L2:扩展用例 + diff --git a/test/scripts/readme.md b/test/scripts/readme.md new file mode 100644 index 00000000..e574ff01 --- /dev/null +++ b/test/scripts/readme.md @@ -0,0 +1,119 @@ +# pytest 测试框架 for hdc auto test + +## 参数指导 + +参数可在pytest.ini中配置,也可以在命令行中配置,优先级:命令行 > pytest.ini +-s: 显示输出调试信息,包括print打印的信息,但是不会写入到report +-v: 显示更详细的信息 +-n:支持多线程运行脚本(需要保持用例彼此独立) +--reruns NUM:失败用例重跑次数 +-x:表示只要有一个用例报错,那么测试停止 +-k:模糊匹配字符串进行用例跑测 +-m: 标记用例Level执行级别 + +## 目录结构 + +目录结构如下: + +```shell +~/hdc/test/scripts/ +├─reports # 测试报告目录 +├─resource # 测试资源文件,存放测试过程中使用到的文件,可使用prepare.py进行资源准备 +├─testModule +| ├─output # 命令行输出文件,例如:重定向文件,zip文件 +| ├─test_hdc_base.py # hdc基础测试 +| ├─test_hdc_file.py # hdc文件测试 +| └─utils.py # 工具 +├─main.py # 测试用例执行入口 +├─prepare.py # 资源准备脚本 +├─pytest.ini # pytest配置文件 +└─requirements.txt # 依赖文件 +``` + +## 测试用例编写 + +### 1. 新建测试套(py文件) + +建议文件名格式为:test_hdc_模块名.py + +### 2. 编写测试用例 + +```python +import pytest +from utils import GP, check_version, load_gp # 注意这里load_gp不能缺省 + +class TestClassExample: + test_table = ['A', 'B', 'C'] + @classmethod + def setup_class(self): + print("这里配置测试类执行前的操作") + + + @classmethod + def teardown_class(self): + print("这里配置测试类执行后的操作") + + + @pytest.mark.自定义标签 # 这里配置用例自定义标签,在pytest.ini中可配置自定义标签参数,以运行标记的测试用例 + @pytest.mark.repeat(2) # 这里配置用例重跑次数 + @check_version("Ver: 3.1.0a") # 这里配置用例最低可执行的版本,低于该版本的环境将跳过用例 + @pytest.mark.parametrize("test_item", file_table) # 这里配置参数化,支持列表,元组,字典 + def test_example(self, test_item): + assert test_item in self.test_table # 这里编写测试用例,支持assert断言 +``` + +## 测试资源配置 + +进入scripts目录,配置环境准备,执行以下命令,新环境执行一次资源环境配置即可,重跑无须二次执行: + +```shell +python prepare.py +``` + +## 测试执行 + +配置完成环境后即可执行测试用例,执行用例有以下两种方式 + +### 方式一 + +```shell +python main.py +``` + +执行参数在pytest.main中配置 + +### 方式二 + +- 执行所有用例 + +```shell +pytest ./ +``` + +- 执行指定目录下所有用例 + +```shell +pytest ./testModule/ +``` + +- 执行指定测试文件 + +```shell +pytest ./testModule/test_hdc_base.py +``` + +- 执行指定测试用例类 + +```shell +pytest testModule/test_hdc_base.py::TestClassExample +``` + +- 执行指定测试用例 + +```shell +pytest testModule/test_hdc_base.py::TestClassExample::test_example +``` + +## 测试报告 + +执行python main.py后,会在reports目录下生成测试报告 diff --git a/test/scripts/requirements.txt b/test/scripts/requirements.txt new file mode 100644 index 00000000..974abb13 --- /dev/null +++ b/test/scripts/requirements.txt @@ -0,0 +1,10 @@ +pytest +allure-pytest +pytest-xdist +pytest-ordering +pytest-rerunfailures +pytest-testreport +pytest-repeat +setuptools +Jinja2 +requests \ No newline at end of file diff --git a/test/scripts/testModule/test_hdc_base.py b/test/scripts/testModule/test_hdc_base.py new file mode 100644 index 00000000..daf03243 --- /dev/null +++ b/test/scripts/testModule/test_hdc_base.py @@ -0,0 +1,107 @@ +#!/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. +import time +import pytest + +from utils import GP, check_hdc_cmd, check_hdc_targets, check_rom, check_hdc_version, get_shell_result,\ + run_command_with_timeout, check_shell, get_remote_path, get_local_path, load_gp + + +def clear_and_restart(): + check_hdc_cmd("kill") + check_hdc_cmd("start") + check_hdc_cmd("wait") + check_hdc_cmd("shell rm -rf data/local/tmp/it_*") + check_hdc_cmd("shell mkdir data/local/tmp/it_send_dir") + + +class TestListTarget: + @pytest.mark.L0 + def test_init(self): + clear_and_restart() + + def test_list_targets(self): + # 这个测试方法也会使用 setup_class 中初始化的环境 + assert check_hdc_targets() + time.sleep(3) + + +class TestROM: + @pytest.mark.L0 + def test_hdcd_rom(self): + baseline = 2200 # 2200KB + assert check_rom(baseline) + + +class TestVersion: + @pytest.mark.L0 + def test_version_cmd(self): + version = "Ver: 3.1.0a" + assert check_hdc_version("-v", version) + assert check_hdc_version("version", version) + assert check_hdc_version("checkserver", version) + + +class TestTargetKey: + @pytest.mark.L0 + def test_target_key(self): + device_key = get_shell_result(f"list targets").split("\r\n")[0] + hdcd_pid = get_shell_result(f"-t {device_key} shell pgrep -x hdcd").split("\r\n")[0] + assert hdcd_pid.isdigit() + + +class TestTargetCommand: + @pytest.mark.L0 + def test_target_cmd(self): + assert check_hdc_targets() + check_hdc_cmd("target boot") + start_time = time.time() + run_command_with_timeout(f"{GP.hdc_head} wait", 30) # reboot takes up to 30 seconds + time.sleep(3) # sleep 3s to wait for the device to boot + run_command_with_timeout(f"{GP.hdc_head} wait", 30) # reboot takes up to 30 seconds + end_time = time.time() + print(f"command exec time {end_time - start_time}") + time.sleep(3) # sleep 3s to wait for the device to connect channel + assert (end_time - start_time) > 8 # Reboot takes at least 8 seconds + + @pytest.mark.L0 + def test_target_mount(self): + assert (check_hdc_cmd("target mount", "Mount finish" or "[Fail]Operate need running as root")) + remount_vendor = get_shell_result(f'shell "mount |grep /vendor |head -1"') + print(remount_vendor) + assert "rw" in remount_vendor + remount_system = get_shell_result(f'shell "cat proc/mounts | grep /system |head -1"') + print(remount_system) + assert "rw" in remount_system + + +class TestSwitch: + @pytest.mark.L0 + @pytest.mark.repeat(1) + def test_file_switch_off(self): + assert check_hdc_cmd("shell param set persist.hdc.control.file false") + assert check_shell(f"shell param get persist.hdc.control.file", "false") + assert check_shell(f"file send {get_local_path('small')} {get_remote_path('it_small')}", + "debugging is not allowed") + assert check_shell(f"file recv {get_remote_path('it_small')} {get_local_path('small_recv')}", + "debugging is not allowed") + + @pytest.mark.L0 + @pytest.mark.repeat(1) + def test_file_switch_on(self): + assert check_hdc_cmd("shell param set persist.hdc.control.file true") + assert check_shell(f"shell param get persist.hdc.control.file", "true") + assert check_hdc_cmd(f"file send {get_local_path('small')} {get_remote_path('it_small')}") + assert check_hdc_cmd(f"file recv {get_remote_path('it_small')} {get_local_path('small_recv')}") \ No newline at end of file diff --git a/test/scripts/testModule/test_hdc_file.py b/test/scripts/testModule/test_hdc_file.py new file mode 100644 index 00000000..edd362cd --- /dev/null +++ b/test/scripts/testModule/test_hdc_file.py @@ -0,0 +1,333 @@ +#!/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. +import os +import pytest + +from utils import GP, check_hdc_cmd, check_hdc_targets, check_soft_local, check_soft_remote,\ + check_shell, rmdir, check_version, get_local_path, get_remote_path, make_multiprocess_file, load_gp + + +def clear_env(): + check_hdc_cmd("shell rm -rf data/local/tmp/it_*") + check_hdc_cmd("shell mkdir data/local/tmp/it_send_dir") + + +def list_targets(): + assert check_hdc_targets() + + +class TestFileCompress: + compress_file_table = [ + ("medium", "it_medium_z"), + ("word_100M.txt", "word_100M_compress.txt") + ] + + @pytest.mark.L1 + @pytest.mark.repeat(1) + @check_version("Ver: 3.1.0e") + @pytest.mark.parametrize("local_path, remote_path", compress_file_table) + def test_file_compress(self, local_path, remote_path): + clear_env() + assert check_hdc_cmd(f"file send -z {get_local_path(local_path)} {get_remote_path(remote_path)}") + assert check_hdc_cmd(f"file recv -z {get_remote_path(remote_path)} {get_local_path(f'{local_path}_recv')}") + + +class TestFileBase: + base_file_table = [ + ("empty", "it_empty"), + ("small", "it_small"), + ("medium", "it_medium"), + ("large", "it_large"), + ("word_100M.txt", "word_100M") + ] + + @pytest.mark.L0 + @pytest.mark.repeat(2) + @pytest.mark.parametrize("local_path, remote_path", base_file_table) + def test_empty_file(self, local_path, remote_path): + clear_env() + assert check_hdc_cmd(f"file send {get_local_path(local_path)} {get_remote_path(remote_path)}") + assert check_hdc_cmd(f"file recv {get_remote_path(remote_path)} {get_local_path(f'{local_path}_recv')}") + + +class TestDirBase: + @pytest.mark.L0 + @pytest.mark.repeat(2) + def test_empty_dir(self): + clear_env() + assert check_shell(f"file send {get_local_path('empty_dir')} {get_remote_path('it_empty_dir')}", + "the source folder is empty") + assert check_hdc_cmd("shell mkdir data/local/tmp/it_empty_dir_recv") + assert check_shell(f"file recv {get_remote_path('it_empty_dir_recv')} {get_local_path('empty_dir_recv')}", + "the source folder is empty") + + @pytest.mark.L0 + @pytest.mark.repeat(2) + def test_long_path(self): + clear_env() + assert check_hdc_cmd(f"file send {get_local_path('deep_test_dir')} {get_remote_path('it_send_dir')}", + is_single_dir=False) + assert check_hdc_cmd(f"file recv {get_remote_path('it_send_dir/deep_test_dir')} " + f"{get_local_path('recv_test_dir')}", + is_single_dir=False) + + @pytest.mark.L0 + @pytest.mark.repeat(2) + def test_recv_dir(self): + if os.path.exists(get_local_path('it_problem_dir')): + rmdir(get_local_path('it_problem_dir')) + assert check_hdc_cmd(f"shell rm -rf {get_remote_path('it_problem_dir')}") + assert check_hdc_cmd(f"shell rm -rf {get_remote_path('problem_dir')}") + assert make_multiprocess_file(get_local_path('problem_dir'), get_remote_path(''), 'send', 1, "dir") + assert check_hdc_cmd(f"shell mv {get_remote_path('problem_dir')} {get_remote_path('it_problem_dir')}") + assert make_multiprocess_file(get_local_path(''), get_remote_path('it_problem_dir'), 'recv', 1, "dir") + + +class TestDirMix: + muti_num = 5 # the count of multiprocess file + file_table = ['empty', 'medium', 'small'] + + @classmethod + def setup_class(self): + pass + + @classmethod + def teardown_class(self): + for test_item in self.file_table: + for i in range(0, self.muti_num - 1): + rmdir(get_local_path(f"{test_item}_recv_{i}")) + + @pytest.mark.L1 + @pytest.mark.repeat(2) + @pytest.mark.parametrize("test_item", file_table) + def test_mix_file(self, test_item): + assert make_multiprocess_file(get_local_path(f'{test_item}'), get_remote_path(f'it_{test_item}'), + 'send', self.muti_num, "file") + assert make_multiprocess_file(get_local_path(f'{test_item}_recv'), get_remote_path(f'it_{test_item}'), + 'recv', self.muti_num, "file") + + +class TestFileNoExist: + remote_unexist_path = f"{get_remote_path('it_no_exist/deep_test_dir/')}" + + @pytest.mark.L0 + @pytest.mark.repeat(2) + @pytest.mark.parametrize("test_item", ['empty', 'medium', 'small', 'problem_dir']) + def test_no_exist_path(self, test_item): + check_hdc_cmd(f"shell rm -rf {get_remote_path('it_no_exist*')}") + local_unexist_path = get_local_path(f'{(os.path.join("recv_no_exist", "deep_test_dir", f"recv_{test_item}"))}') + if os.path.exists(get_local_path('recv_no_exist')): + rmdir(get_local_path('recv_no_exist')) + assert check_hdc_cmd(f"file send " + f"{get_local_path(f'{test_item}')} {self.remote_unexist_path}/it_{test_item}") + assert check_hdc_cmd(f"file recv {self.remote_unexist_path}/it_{test_item} " + f"{local_unexist_path}") + + @pytest.mark.L0 + @pytest.mark.repeat(2) + @pytest.mark.parametrize("test_item", ['empty', 'medium', 'small']) + def test_no_exist_path_with_seperate(self, test_item): + check_hdc_cmd(f"shell rm -rf {get_remote_path('it_no_exist*')}") + local_unexist_path = get_local_path(f'{(os.path.join("recv_no_exist", "deep_test_dir"))}') + if os.path.exists(get_local_path('recv_no_exist')): + rmdir(get_local_path('recv_no_exist')) + assert check_hdc_cmd(f"file send " + f"{get_local_path(f'{test_item}')} {self.remote_unexist_path}/") + assert check_hdc_cmd(f"file recv {self.remote_unexist_path}/{test_item} " + f"{local_unexist_path}{os.sep}") + + +class TestFileNoExistBundelPath: + remote_unexist_path = f"{get_remote_path('it_no_exist/deep_test_dir/')}" + data_storage_el2_path = "data/storage/el2/base" + + @classmethod + def setup_class(self): + check_shell(f"shell mkdir -p mnt/debug/100/debug_hap/{GP.debug_app}/{self.data_storage_el2_path}") + + @pytest.mark.L0 + @pytest.mark.repeat(3) + @check_version("Ver: 3.1.0e") + @pytest.mark.parametrize("test_item", ['empty', 'medium', 'small', 'problem_dir']) + def test_no_exist_bundle_path(self, test_item): + check_hdc_cmd(f"shell -b {GP.debug_app} rm -rf {self.data_storage_el2_path}/it_no_exist/") + local_unexist_path = get_local_path( + f'{(os.path.join("recv_no_exist", "deep_test_dir", f"recv_{test_item}"))}') + if os.path.exists(get_local_path('recv_no_exist')): + rmdir(get_local_path('recv_no_exist')) + + assert check_hdc_cmd(f"shell -b {GP.debug_app} ls {self.data_storage_el2_path}/it_no_exist", + "No such file or directory") + assert not os.path.exists(get_local_path('recv_no_exist')) + assert check_hdc_cmd(f"file send -b {GP.debug_app} " + f"{get_local_path(f'{test_item}')} {self.remote_unexist_path}/it_{test_item}") + assert check_hdc_cmd(f"file recv -b {GP.debug_app} {self.remote_unexist_path}/it_{test_item} " + f"{local_unexist_path}") + + +class TestFileExtend: + @pytest.mark.L0 + @pytest.mark.repeat(1) + def test_node_file(self): + assert check_hdc_cmd(f"file recv {get_remote_path('../../../sys/power/state')} {get_local_path('state')}") + assert check_hdc_cmd(f"file recv {get_remote_path('../../../sys/firmware/fdt')} {get_local_path('fdt')}") + + @pytest.mark.L0 + @pytest.mark.repeat(1) + def test_running_file(self): + assert check_hdc_cmd(f"file recv system/bin/hdcd {get_local_path('running_recv')}") + + @pytest.mark.L2 + @pytest.mark.repeat(2) + def test_soft_link(self): + assert check_soft_local(get_local_path('small'), get_local_path('soft_small'), + get_remote_path('it_small_soft')) + assert check_soft_remote('it_small_soft', get_remote_path('it_soft_small'), + get_local_path('recv_soft_small')) + + +class TestFileError: + @pytest.mark.L0 + @pytest.mark.repeat(1) + def test_file_error(self): + assert check_hdc_cmd("target mount") + assert check_shell( + f"file recv", + "[Fail]There is no local and remote path" + ) + assert check_shell( + f"file send", + "[Fail]There is no local and remote path" + ) + assert check_hdc_cmd(f"shell rm -rf {get_remote_path('../../../large')}") + assert check_hdc_cmd(f"shell param set persist.hdc.control.file false") + assert check_shell( + f"file send {get_local_path('small')} {get_remote_path('it_small_false')}", + "debugging is not allowed" + ) + assert check_hdc_cmd(f"shell param set persist.hdc.control.file true") + assert check_hdc_cmd(f"file send {get_local_path('small')} {get_remote_path('it_small_true')}") + + +class TestFileBundleOptionNormal: + data_storage_el2_path = "data/storage/el2/base" + + @classmethod + def setup_class(self): + check_shell(f"shell rm -rf mnt/debug/100/debug_hap/{GP.debug_app}/{self.data_storage_el2_path}/it*") + check_shell(f"shell mkdir -p mnt/debug/100/debug_hap/{GP.debug_app}/{self.data_storage_el2_path}") + + @classmethod + def teardown_class(self): + pass + + @pytest.mark.L0 + @check_version("Ver: 3.1.0e") + @pytest.mark.parametrize("test_item", ['empty', 'medium', 'small', 'problem_dir']) + def test_file_option_bundle_normal(self, test_item): + if test_item == 'problem_dir' and os.path.exists(get_local_path(f'recv_bundle_{test_item}')): + rmdir(get_local_path(f'recv_bundle_{test_item}')) + assert check_hdc_cmd(f"file send -b {GP.debug_app} " + f"{get_local_path(f'{test_item}')} {self.data_storage_el2_path}/it_{test_item}") + assert check_hdc_cmd(f"file recv -b {GP.debug_app} {self.data_storage_el2_path}/it_{test_item} " + f"{get_local_path(f'recv_bundle_{test_item}')}") + + +class TestFileBundleOptionError: + data_storage_el2_path = "data/storage/el2/base" + error_table = [ + # 测试空文件夹发送和接收 + (f"file send -b {GP.debug_app} {get_local_path('empty_dir')} {get_remote_path('it_empty_dir')}", + "the source folder is empty"), + + # 测试缺少本地和远程路径 + (f"file send -b {GP.debug_app}", "There is no local and remote path"), + (f"file recv -b {GP.debug_app}", "There is no local and remote path"), + + # 测试错误优先级 + (f"file send -b ./{GP.debug_app}", "There is no local and remote path"), + (f"file recv -b ./{GP.debug_app}", "There is no local and remote path"), + + # 测试缺少 bundle 参数 + (f"file recv -b", "[E005003]"), + (f"file send -b", "[E005003]"), + + # 测试本地和远程路径错误 + (f"file send -b ./{GP.debug_app} {get_local_path('small')} {get_remote_path('it_small')}", "[E005101]"), + (f"file recv -b ./{GP.debug_app} {get_local_path('small')} {get_remote_path('it_small')}", "[E005101]"), + + # 测试无效的 bundle 参数 + (f"file send -b ./{GP.debug_app} {get_local_path('small')} {get_remote_path('it_small')}", "[E005101]"), + (f"file send -b com.AAAA {get_local_path('small')} {get_remote_path('it_small')}", "[E005101]"), + (f"file send -b 1 {get_local_path('small')} {get_remote_path('it_small')}", "[E005101]"), + (f"file send -b {get_local_path('small')} {get_remote_path('it_small')}", "There is no remote path"), + + # 测试远程路径错误 + (f"file recv -b ./{GP.debug_app} {get_remote_path('it_small')} {get_local_path('small_recv')}", "[E005101]"), + + # 测试路径逃逸 + (f"file send -b {GP.debug_app} {get_local_path('small')} ../../../it_small", "[E005102]"), + (f"file recv -b {GP.debug_app} ../../../it_small {get_local_path('small_recv')}", "[E005102]"), + ] + outside_error = "[E005102]" + outside_table = [ + # bundle根目录 逃逸 + ("..", True), + ("../..", True), + ("../../..", True), + ("../../../..", True), + ("../.", True), + ("./..", True), + ("../", True), + (f"../{GP.debug_app}_extra/{data_storage_el2_path}/", True), + (f"../{GP.debug_app}_notexsit/{data_storage_el2_path}/", True), + (f"../{GP.debug_app}_notexsit/", True), + (f"./../../../../../../../../../../aa", True), + + # bundle根目录 未逃逸 + (".", False), + ("./", False), + ("./.", False), + ("...", False), + (f"../../../../../../../../../../../mnt/debug/100/debug_hap/{GP.debug_app}/", False), + ] + + @classmethod + def setup_class(self): + check_shell(f"shell rm -rf mnt/debug/100/debug_hap/{GP.debug_app}/{self.data_storage_el2_path}/it*") + check_shell(f"shell mkdir -p mnt/debug/100/debug_hap/{GP.debug_app}/{self.data_storage_el2_path}") + check_shell(f"shell rm -rf mnt/debug/100/debug_hap/{GP.debug_app}_extra/{self.data_storage_el2_path}/*") + check_shell(f"shell mkdir -p mnt/debug/100/debug_hap/{GP.debug_app}_extra/{self.data_storage_el2_path}/") + + @classmethod + def teardown_class(self): + pass + + @pytest.mark.L0 + @check_version("Ver: 3.1.0e") + @pytest.mark.parametrize("command, expected", error_table) + def test_file_option_bundle_error_parametrized(self, command, expected): + assert check_shell(command, expected) + + @pytest.mark.parametrize("remote_path, is_outside", outside_table) + @pytest.mark.L0 + @check_version("Ver: 3.1.0e") + def test_file_option_bundle_check_outside_parametrized(self, remote_path, is_outside): + if is_outside: + assert check_shell(f"file send -b {GP.debug_app} {get_local_path('small')} {remote_path}", + self.outside_error) + else: + assert not check_shell(f"file send -b {GP.debug_app} {get_local_path('small')} {remote_path}", + self.outside_error) \ No newline at end of file diff --git a/test/scripts/testModule/test_hdc_fport.py b/test/scripts/testModule/test_hdc_fport.py new file mode 100644 index 00000000..d71af08a --- /dev/null +++ b/test/scripts/testModule/test_hdc_fport.py @@ -0,0 +1,87 @@ +#!/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. +import pytest +from utils import GP, check_shell_any_device, check_hdc_cmd, get_shell_result, load_gp + + +class TestFilePerformance: + @pytest.mark.L0 + def test_fport_cmd_output(self): + local_port = 18070 + remote_port = 11080 + fport_arg = f"tcp:{local_port} tcp:{remote_port}" + assert check_hdc_cmd(f"fport {fport_arg}", "Forwardport result:OK") + assert check_shell_any_device(f"netstat -ano", "LISTENING", False)[0] + assert check_shell_any_device(f"netstat -ano", f"{local_port}", False)[0] + assert check_hdc_cmd(f"fport ls", fport_arg) + assert check_hdc_cmd(f"fport rm {fport_arg}", "success") + + @pytest.mark.L0 + def test_rport_cmd_output(self): + local_port = 17090 + remote_port = 11080 + rport_arg = f"tcp:{local_port} tcp:{remote_port}" + assert check_hdc_cmd(f"rport {rport_arg}", "Forwardport result:OK") + netstat_line = get_shell_result(f'shell "netstat -anp | grep {local_port}"') + assert "LISTEN" in netstat_line + assert "hdcd" in netstat_line + fport_list = get_shell_result(f"fport ls") + assert "Reverse" in fport_list + assert rport_arg in fport_list + assert check_hdc_cmd(f"fport rm {rport_arg}", "success") + + @pytest.mark.L0 + def test_fport_cmd(self): + fport_list = [] + rport_list = [] + start_port = 10000 + end_port = 10020 + for i in range(start_port, end_port): + fport = f"tcp:{i+100} tcp:{i+200}" + rport = f"tcp:{i+300} tcp:{i+400}" + localabs = f"tcp:{i+500} localabstract:{f'helloworld.com.app.{i+600}'}" + fport_list.append(fport) + rport_list.append(rport) + fport_list.append(localabs) + + for fport in fport_list: + assert check_hdc_cmd(f"fport {fport}", "Forwardport result:OK") + assert check_hdc_cmd(f"fport {fport}", "TCP Port listen failed at") + assert check_hdc_cmd("fport ls", fport) + + for fport in fport_list: + assert check_hdc_cmd(f"fport rm {fport}", "success") + assert not check_hdc_cmd("fport ls", fport) + + for rport in rport_list: + assert check_hdc_cmd(f"rport {rport}", "Forwardport result:OK") + assert check_hdc_cmd(f"rport {rport}", "TCP Port listen failed at") + assert check_hdc_cmd("rport ls", rport) or check_hdc_cmd("fport ls", rport) + + for rport in rport_list: + assert check_hdc_cmd(f"fport rm {rport}", "success") + assert not check_hdc_cmd("rport ls", fport) and not check_hdc_cmd("fport ls", fport) + + task_str1 = "tcp:33333 tcp:33333" + assert check_hdc_cmd(f"fport {task_str1}", "Forwardport result:OK") + assert check_hdc_cmd(f"fport rm {task_str1}", "success") + assert check_hdc_cmd(f"fport {task_str1}", "Forwardport result:OK") + assert check_hdc_cmd(f"fport rm {task_str1}", "success") + + task_str2 = "tcp:44444 tcp:44444" + assert check_hdc_cmd(f"rport {task_str2}", "Forwardport result:OK") + assert check_hdc_cmd(f"fport rm {task_str2}", "success") + assert check_hdc_cmd(f"rport {task_str2}", "Forwardport result:OK") + assert check_hdc_cmd(f"fport rm {task_str2}", "success") diff --git a/test/scripts/testModule/test_hdc_help.py b/test/scripts/testModule/test_hdc_help.py new file mode 100644 index 00000000..f102a369 --- /dev/null +++ b/test/scripts/testModule/test_hdc_help.py @@ -0,0 +1,23 @@ +#!/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. +import pytest +from utils import GP, check_hdc_cmd, load_gp + + +class TestHdcHelp: + @pytest.mark.L0 + def test_hdc_help(self): + assert check_hdc_cmd("help", "Generate public") + assert check_hdc_cmd("help --verbose", 'ark:pid@tid@Debugger fport ls') \ No newline at end of file diff --git a/test/scripts/testModule/test_hdc_install.py b/test/scripts/testModule/test_hdc_install.py new file mode 100644 index 00000000..49b13a4d --- /dev/null +++ b/test/scripts/testModule/test_hdc_install.py @@ -0,0 +1,103 @@ +#!/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. +import pytest +from utils import GP, check_app_install, check_app_install_multi, check_app_uninstall,\ + check_app_uninstall_multi, check_hdc_cmd, get_local_path, load_gp + + +class TestInstallBase: + hap_tables = { + "AACommand07.hap" : "com.example.aacommand07", + "AACommand08.hap" : "com.example.aacommand08" + } + hsp_tables = { + "libA_v10001.hsp" : "com.example.liba", + "libB_v10001.hsp" : "com.example.libb", + } + hsp_hap_tables = { + "AACommandpackage.hap" : "com.example.actsaacommandtestatest", + "libB_v10001.hsp" : "com.example.libb", + } + + # 来自原hdc_normal_test.py的基础install 用例 + @pytest.mark.L0 + @pytest.mark.repeat(2) + @pytest.mark.parametrize("package_hap, hap_name_default", hap_tables.items()) + def test_hap_install(self, package_hap, hap_name_default): + assert check_hdc_cmd(f"install -r {get_local_path(f'{package_hap}')}", + bundle=f"{hap_name_default}") + assert check_app_uninstall(f"{hap_name_default}") + + @pytest.mark.L1 + @pytest.mark.repeat(2) + @pytest.mark.parametrize("package_hap, hap_name_default", hap_tables.items()) + def test_install_hap(self, package_hap, hap_name_default): + + # default + assert check_app_install(package_hap, hap_name_default) + assert check_app_uninstall(hap_name_default) + + # -r + assert check_app_install(package_hap, hap_name_default, "-r") + assert check_app_uninstall(hap_name_default) + + # -k + assert check_app_install(package_hap, hap_name_default, "-r") + assert check_app_uninstall(hap_name_default, "-k") + + # -s + assert check_app_install(package_hap, hap_name_default, "-s") + + @pytest.mark.L0 + @pytest.mark.repeat(2) + @pytest.mark.parametrize("package_hsp, hsp_name_default", hsp_tables.items()) + def test_install_hsp(self, package_hsp, hsp_name_default): + assert check_app_install(package_hsp, hsp_name_default, "-s") + assert check_app_uninstall(hsp_name_default, "-s") + assert check_app_install(package_hsp, hsp_name_default) + + @pytest.mark.L0 + @pytest.mark.repeat(2) + def test_install_multi_hap(self): + # default multi hap + assert check_app_install_multi(self.hap_tables) + assert check_app_uninstall_multi(self.hap_tables) + assert check_app_install_multi(self.hap_tables, "-s") + assert check_app_install_multi(self.hap_tables, "-r") + assert check_app_uninstall_multi(self.hap_tables, "-k") + + + @pytest.mark.L0 + @pytest.mark.repeat(2) + def test_install_multi_hsp(self): + # default multi hsp -s + assert check_app_install_multi(self.hsp_tables, "-s") + assert check_app_uninstall_multi(self.hsp_tables, "-s") + assert check_app_install_multi(self.hsp_tables) + + @pytest.mark.L0 + @pytest.mark.repeat(2) + def test_install_hsp_and_hap(self): + #default multi hsp and hsp + assert check_app_install_multi(self.hsp_hap_tables) + assert check_app_install_multi(self.hsp_hap_tables, "-s") + + @pytest.mark.L0 + @pytest.mark.repeat(2) + def test_install_dir(self): + package_haps_dir = "app_dir" + hap_name_default_default = "com.example.aacommand07" + assert check_app_install(package_haps_dir, hap_name_default_default) + assert check_app_uninstall(hap_name_default_default) \ No newline at end of file diff --git a/test/scripts/testModule/test_hdc_performance.py b/test/scripts/testModule/test_hdc_performance.py new file mode 100644 index 00000000..0a7ab309 --- /dev/null +++ b/test/scripts/testModule/test_hdc_performance.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. +import pytest +from utils import GP, check_cmd_time, check_hdc_cmd, check_rate, get_local_path, get_remote_path, load_gp + + +def clear_env(): + check_hdc_cmd("shell rm -rf data/local/tmp/it_*") + check_hdc_cmd("shell mkdir data/local/tmp/it_send_dir") + + +class TestShellPerformance: + @pytest.mark.L0 + def test_shell_cmd_timecost(self): + assert check_cmd_time( + cmd="shell \"ps -ef | grep hdcd\"", + pattern="hdcd", + duration=None, + times=10) + + @pytest.mark.L0 + def test_shell_huge_cat(self): + assert check_hdc_cmd(f"file send {get_local_path('word_100M.txt')} {get_remote_path('it_word_100M.txt')}") + assert check_cmd_time( + cmd=f"shell cat {get_remote_path('it_word_100M.txt')}", + pattern=None, + duration=10000, # 10 seconds + times=10) + + +class TestFilePerformance: + @pytest.mark.L0 + @pytest.mark.repeat(1) + def test_rate(self): + clear_env() + assert check_rate(f"file send {get_local_path('large')} {get_remote_path('it_large')}", 18000) + assert check_rate(f"file recv {get_remote_path('it_large')} {get_local_path('large_recv')}", 18000) + \ No newline at end of file diff --git a/test/scripts/testModule/test_hdc_server.py b/test/scripts/testModule/test_hdc_server.py new file mode 100644 index 00000000..df7701a1 --- /dev/null +++ b/test/scripts/testModule/test_hdc_server.py @@ -0,0 +1,40 @@ +#!/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. +import os +import time +import pytest +from utils import GP, check_cmd_block, check_hdc_cmd, load_gp + + +class TestHdcServer: + @pytest.mark.L0 + def test_hdc_server_foreground(self): + port = os.getenv('OHOS_HDC_SERVER_PORT') + if port is None: + port = 8710 + assert check_hdc_cmd("kill", "Kill server finish") + assert check_cmd_block(f"{GP.hdc_exe} -m", f"port: {port}", timeout=5) + assert check_hdc_cmd("start") + time.sleep(3) # sleep 3s to wait for the device to connect channel + + @pytest.mark.L0 + def test_server_kill(self): + assert check_hdc_cmd("kill", "Kill server finish") + assert check_hdc_cmd("start server") + time.sleep(3) # sleep 3s to wait for the device to connect channel + assert check_hdc_cmd("kill -r", "Start server finish") + assert check_hdc_cmd("start -r", "hdc start server") + assert check_hdc_cmd("checkserver", "Ver") + time.sleep(3) # sleep 3s to wait for the device to connect channel \ No newline at end of file diff --git a/test/scripts/testModule/test_hdc_shell.py b/test/scripts/testModule/test_hdc_shell.py new file mode 100644 index 00000000..239a63c9 --- /dev/null +++ b/test/scripts/testModule/test_hdc_shell.py @@ -0,0 +1,89 @@ +#!/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. +import pytest +import os +import time +import multiprocessing + +from utils import GP, check_hdc_cmd, check_shell, check_version, get_shell_result, run_command_with_timeout, load_gp + + +class TestShellHilog: + #子进程执行函数 + def new_process_run(self, cmd): + # 重定向 stdout 和 stderr 到 /dev/null + with open(os.devnull, 'w') as devnull: + old_stdout = os.dup2(devnull.fileno(), 1) # 重定向 stdout + old_stderr = os.dup2(devnull.fileno(), 2) # 重定向 stderr + try: + # 这里是子进程的代码,不会有任何输出到控制台 + check_shell(f'{cmd}') + finally: + # 恢复原始的 stdout 和 stderr + os.dup2(old_stdout, 1) + os.dup2(old_stderr, 2) + + @pytest.mark.L0 + def test_hilog_exit_after_hdc_kill(self): + # 新开进程执行hdc shell hilog,防止阻塞主进程 + p = multiprocessing.Process(target=self.new_process_run, args=("shell hilog",)) + p.start() + time.sleep(1) + hilog_pid = get_shell_result(f'shell pidof hilog') + hilog_pid = hilog_pid.replace("\r\n", "") + assert hilog_pid.isdigit() + assert check_hdc_cmd(f'kill', "Kill server finish") + assert check_hdc_cmd("start") + time.sleep(3) # sleep 3s to wait for the device to connect channel + run_command_with_timeout(f"{GP.hdc_head} wait", 3) # wait 3s for the device to connect channel + hilog_pid2 = get_shell_result(f'shell pidof hilog') + assert hilog_pid2 == '' + p.join() + + +class TestShellBundleOption: + a_long = "a" * 129 + a_short = "a" * 6 + test_bundle_data = [ + ("-b ""com.XXXX.not.exist.app", "pwd", "[Fail][E003001]"), + ("-b ""../../../../", "pwd", "[Fail][E003001]"), + ("-b ""././././pwd", "pwd", "[Fail][E003001]"), + ("-b ""/", "pwd", "[Fail][E003001]"), + ("-b "f"{GP.debug_app}", "", "[Fail][E003002]"), + (f"-b {a_long}", "pwd", "[Fail][E003001]"), + (f"-b {a_short}", "pwd", "[Fail][E003001]"), + ("-b #########", "pwd", "[Fail][E003001]"), + ("-param 1234567890", "pwd", "[Fail][E003003]"), + ("-basd {GP.debug_app}", "pwd", "[Fail][E003003]"), + ("- {GP.debug_app}", "ls", "[Fail][E003003]"), + ("-b", "ls", "[Fail][E003001]"), + ("-b", "", "[Fail][E003005]"), + ("-t -b {GP.debug_app}", "ls", "[Fail][E003003]"), + ("ls -b {GP.debug_app}", "", "No such file or directory"), + ("-b -b {GP.debug_app}", "ls", "[Fail][E003001]"), + ("--b {GP.debug_app}", "", "[Fail][E003003]"), + ] + + @classmethod + def setup_class(self): + data_storage_el2_path = "data/storage/el2/base" + check_shell(f"shell mkdir -p mnt/debug/100/debug_hap/{GP.debug_app}/{data_storage_el2_path}") + + @pytest.mark.L0 + @check_version("Ver: 3.1.0e") + @pytest.mark.parametrize("bundle_option, command, expected_output", test_bundle_data) + def test_bundle_option_matrix(self, bundle_option, command, expected_output): + test_command = f"shell {bundle_option} {command}" + assert check_shell(test_command, expected_output) \ No newline at end of file diff --git a/test/scripts/testModule/test_hdc_smode.py b/test/scripts/testModule/test_hdc_smode.py new file mode 100644 index 00000000..f0acdbd4 --- /dev/null +++ b/test/scripts/testModule/test_hdc_smode.py @@ -0,0 +1,49 @@ +#!/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. +import pytest +import time +from utils import GP, check_hdc_cmd, check_shell, get_local_path, run_command_with_timeout, load_gp + + +class TestSmode: + @pytest.mark.L0 + def test_smode_permission(self): + check_shell(f"shell rm -rf data/deep_test_dir") + assert check_hdc_cmd(f'smode -r') + time.sleep(3) + run_command_with_timeout(f"{GP.hdc_head} wait", 3) # wait 3s for the device to connect channel + assert check_shell(f"file send {get_local_path('deep_test_dir')} data/", + "permission denied") + assert check_shell(f"file send {get_local_path('deep_test_dir')} data/", + "[E005005]") + + @pytest.mark.L0 + def test_smode_r(self): + assert check_hdc_cmd(f'smode -r') + time.sleep(3) # sleep 3s to wait for the device to connect channel + run_command_with_timeout(f"{GP.hdc_head} wait", 3) # wait 3s for the device to connect channel + time.sleep(3) # sleep 3s to wait for the device to connect channel + run_command_with_timeout(f"{GP.hdc_head} wait", 3) # wait 3s for the device to connect channel + assert check_shell(f"shell id", "context=u:r:sh:s0") + + @pytest.mark.L0 + def test_smode(self): + assert check_hdc_cmd(f'smode') + time.sleep(3) # sleep 3s to wait for the device to connect channel + run_command_with_timeout(f"{GP.hdc_head} wait", 3) # wait 3s for the device to connect channel + time.sleep(3) # sleep 3s to wait for the device to connect channel + run_command_with_timeout(f"{GP.hdc_head} wait", 3) # wait 3s for the device to connect channel + assert check_shell(f"shell id", "context=u:r:su:s0") + assert not check_hdc_cmd("ls data/log/faultlog/faultlogger | grep hdcd", "hdcd") \ No newline at end of file diff --git a/test/scripts/testModule/test_hdc_tcp.py b/test/scripts/testModule/test_hdc_tcp.py new file mode 100644 index 00000000..eb96eddf --- /dev/null +++ b/test/scripts/testModule/test_hdc_tcp.py @@ -0,0 +1,40 @@ +#!/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. +import pytest +import time +from utils import GP, check_hdc_cmd, get_shell_result, run_command_with_timeout, load_gp + + +class TestTcpByFport: + @pytest.mark.L0 + def test_persist_hdc_mode_tcp(self): + assert check_hdc_cmd(f"shell param set persist.hdc.mode.tcp enable") + time.sleep(5) + run_command_with_timeout("hdc wait", 3) + netstat_listen = get_shell_result(f'shell "netstat -anp | grep tcp | grep hdcd"') + assert "LISTEN" in netstat_listen + assert "hdcd" in netstat_listen + assert check_hdc_cmd(f"shell param set persist.hdc.mode.tcp enable") + time.sleep(5) + run_command_with_timeout("hdc wait", 3) + netstat_listen = get_shell_result(f'shell "netstat -anp | grep tcp | grep hdcd"') + assert "LISTEN" in netstat_listen + assert "hdcd" in netstat_listen + assert check_hdc_cmd(f"shell param set persist.hdc.mode.tcp disable") + time.sleep(5) + run_command_with_timeout("hdc wait", 3) + netstat_listen = get_shell_result(f'shell "netstat -anp | grep tcp | grep hdcd"') + assert "LISTEN" not in netstat_listen + assert "hdcd" not in netstat_listen \ No newline at end of file diff --git a/test/scripts/testModule/test_hdc_tmode.py b/test/scripts/testModule/test_hdc_tmode.py new file mode 100644 index 00000000..f0d42394 --- /dev/null +++ b/test/scripts/testModule/test_hdc_tmode.py @@ -0,0 +1,87 @@ +#!/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. +import pytest +import time +from utils import GP, check_hdc_cmd, get_shell_result, run_command_with_timeout, load_gp + + +class TestPersistMode: + @pytest.mark.L0 + def test_persist_hdc_mode_tcp(self): + assert check_hdc_cmd(f"shell param set persist.hdc.mode.tcp enable") + time.sleep(5) + run_command_with_timeout("hdc wait", 3) + netstat_listen = get_shell_result(f'shell "netstat -anp | grep tcp | grep hdcd"') + assert "LISTEN" in netstat_listen + assert "hdcd" in netstat_listen + assert check_hdc_cmd(f"shell param set persist.hdc.mode.tcp enable") + time.sleep(5) + run_command_with_timeout("hdc wait", 3) + netstat_listen = get_shell_result(f'shell "netstat -anp | grep tcp | grep hdcd"') + assert "LISTEN" in netstat_listen + assert "hdcd" in netstat_listen + assert check_hdc_cmd(f"shell param set persist.hdc.mode.tcp disable") + time.sleep(5) + run_command_with_timeout("hdc wait", 3) + netstat_listen = get_shell_result(f'shell "netstat -anp | grep tcp | grep hdcd"') + assert "LISTEN" not in netstat_listen + assert "hdcd" not in netstat_listen + + @pytest.mark.L0 + def test_persist_hdc_mode_usb(self): + assert check_hdc_cmd(f"shell param set persist.hdc.mode.usb enable") + echo_result = get_shell_result(f'shell "echo 12345"') + assert "12345" not in echo_result + time.sleep(10) + run_command_with_timeout("hdc wait", 3) + echo_result = get_shell_result(f'shell "echo 12345"') + assert "12345" in echo_result + + @pytest.mark.L0 + def test_persist_hdc_mode_tcp_usb(self): + assert check_hdc_cmd(f"shell param set persist.hdc.mode.tcp enable") + time.sleep(5) + run_command_with_timeout("hdc wait", 3) + assert check_hdc_cmd(f"shell param set persist.hdc.mode.usb enable") + time.sleep(10) + run_command_with_timeout("hdc wait", 3) + netstat_listen = get_shell_result(f'shell "netstat -anp | grep tcp | grep hdcd"') + assert "LISTEN" in netstat_listen + assert "hdcd" in netstat_listen + assert check_hdc_cmd(f"shell param set persist.hdc.mode.tcp disable") + time.sleep(5) + run_command_with_timeout("hdc wait", 3) + netstat_listen = get_shell_result(f'shell "netstat -anp | grep tcp | grep hdcd"') + assert "LISTEN" not in netstat_listen + assert "hdcd" not in netstat_listen + + +class TestTmodeCommand: + @pytest.mark.L0 + def test_tmode_port(self): + assert (check_hdc_cmd("tmode port", "Set device run mode successful")) + time.sleep(3) # sleep 3s to wait for the device to connect channel + run_command_with_timeout(f"{GP.hdc_head} wait", 3) # wait 3s for the device to connect channel + time.sleep(3) # sleep 3s to wait for the device to connect channel + run_command_with_timeout(f"{GP.hdc_head} wait", 3) # wait 3s for the device to connect channel + assert (check_hdc_cmd("tmode port 12345")) + time.sleep(3) # sleep 3s to wait for the device to connect channel + run_command_with_timeout(f"{GP.hdc_head} wait", 3) # wait 3s for the device to connect channel + time.sleep(3) # sleep 3s to wait for the device to connect channel + run_command_with_timeout(f"{GP.hdc_head} wait", 3) # wait 3s for the device to connect channel + netstat_port = get_shell_result(f'shell "netstat -anp | grep 12345"') + print(netstat_port) + assert "LISTEN" in netstat_port + assert "hdcd" in netstat_port \ No newline at end of file diff --git a/test/scripts/testModule/test_hdc_usb.py b/test/scripts/testModule/test_hdc_usb.py new file mode 100644 index 00000000..7d30fff1 --- /dev/null +++ b/test/scripts/testModule/test_hdc_usb.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. +import pytest +import time +from utils import GP, check_hdc_cmd, check_hdc_targets, check_shell_any_device, load_gp + + +class TestUsbConnect: + @pytest.mark.L0 + def test_usb_disconnect(self): + # 注意:断连后需要等待一段时间才能重新连接 + + assert check_hdc_targets() + cmd = 'shell "kill -9 `pidof hdcd`"' + check_hdc_cmd(f"{cmd}", "[Fail][E001003] USB communication abnormal, please check the USB communication link.") + time.sleep(3) + assert check_hdc_targets() + + @pytest.mark.L0 + def test_list_targets_multi_usb_device(self): + devices_str = check_shell_any_device(f"{GP.hdc_exe} list targets", None, True) + time.sleep(3) # sleep 3s to wait for the device to connect channel + devices_array = devices_str[1].split('\n') + if devices_array: + for device in devices_array: + if len(device) > 8: + assert check_shell_any_device(f"{GP.hdc_exe} -t {device} shell id", "u:r:")[0] diff --git a/scripts/dev_hdc_test.py b/test/scripts/testModule/utils.py old mode 100755 new mode 100644 similarity index 77% rename from scripts/dev_hdc_test.py rename to test/scripts/testModule/utils.py index a6396715..7e090154 --- a/scripts/dev_hdc_test.py +++ b/test/scripts/testModule/utils.py @@ -1,1077 +1,1004 @@ -#!/usr/bin/env python3 -# -*- coding: utf-8 -*- -# Copyright (C) 2021 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. - -# 0. 运行环境: python 3.10+, pytest -# 1. 修改 GP 中字段 -# 2. pytest [-k case_name_pattern] -# eg. pytest -k file 执行方法名含 file 的用例 - -# 打包 -# pip install pyinstaller -# prepare assert source dir includes your data files -# pyi-makespec -D --add-data assert:assert dev_hdc_test.py -# pyinstaller dev_hdc_test.spec -# 执行 dev_hdc_test.exe - -import csv -import hashlib -import json -import logging -import os -import random -import re -import stat -import shutil -import subprocess -import sys -import threading -import time -from multiprocessing import Process - -import pytest -import pkg_resources - - -class GP(object): - """ Global Parameters - - customize here !!! - """ - hdc_exe = "hdc" - local_path = "resource" - remote_path = "data/local/tmp" - remote_dir_path = "data/local/tmp/it_send_dir" - remote_ip = "auto" - remote_port = 8710 - hdc_head = "hdc" - device_name = "" - targets = [] - tmode = "usb" - changed_testcase = "n" - testcase_path = "ts_windows.csv" - loaded_testcase = 0 - hdcd_rom = "not checked" - debug_app = "com.example.myapplication" - - @classmethod - def init(cls): - logging.basicConfig(level=logging.INFO, - format='%(asctime)s %(filename)s [line:%(lineno)d] %(levelname)s %(message)s', - datefmt='%d %b %Y %H:%M:%S', - ) - logging.basicConfig(level=logging.WARNING, - format='%(asctime)s %(filename)s [line:%(lineno)d] %(levelname)s %(message)s', - datefmt='%d %b %Y %H:%M:%S', - ) - - if os.path.exists(".hdctester.conf"): - cls.load() - cls.start_host() - cls.list_targets() - else: - cls.set_options() - cls.print_options() - cls.start_host() - cls.dump() - return - - - @classmethod - def start_host(cls): - cmd = f"{cls.hdc_exe} start" - res = subprocess.call(cmd.split()) - return res - - @classmethod - def list_targets(cls): - try: - targets = subprocess.check_output(f"{cls.hdc_exe} list targets".split()).split() - except (OSError, IndexError): - targets = [b"failed to auto detect device"] - cls.targets = [targets[0].decode()] - return False - cls.targets = [t.decode() for t in targets] - return True - - - @classmethod - def get_device(cls): - cls.start_host() - cls.list_targets() - if len(cls.targets) > 1: - print("Multiple device detected, please select one:") - for i, t in enumerate(cls.targets): - print(f"{i+1}. {t}") - print("input the nums of the device above:") - cls.device_name = cls.targets[int(input()) - 1] - else: - cls.device_name = cls.targets[0] - if cls.device_name == "failed to auto detect device": - print("No device detected, please check your device connection") - return False - elif cls.device_name == "[empty]": - print("No hdc device detected.") - return False - cls.hdc_head = f"{cls.hdc_exe} -t {cls.device_name}" - return True - - - @classmethod - def dump(cls): - try: - os.remove(".hdctester.conf") - except OSError: - pass - content = filter( - lambda k: not k[0].startswith("__") and not isinstance(k[1], classmethod), cls.__dict__.items()) - json_str = json.dumps(dict(content)) - fd = os.open(".hdctester.conf", os.O_WRONLY | os.O_CREAT, 0o755) - os.write(fd, json_str.encode()) - os.close(fd) - return True - - - @classmethod - def load(cls): - with open(".hdctester.conf") as f: - content = json.load(f) - cls.hdc_exe = content.get("hdc_exe") - cls.local_path = content.get("local_path") - cls.remote_path = content.get("remote_path") - cls.remote_ip = content.get("remote_ip") - cls.hdc_head = content.get("hdc_head") - cls.tmode = content.get("tmode") - cls.device_name = content.get("device_name") - cls.changed_testcase = content.get("changed_testcase") - cls.testcase_path = content.get("testcase_path") - cls.loaded_testcase = content.get("load_testcase") - return True - - - @classmethod - def print_options(cls): - info = "HDC Tester Default Options: \n\n" \ - + f"{'hdc execution'.rjust(20, ' ')}: {cls.hdc_exe}\n" \ - + f"{'local storage path'.rjust(20, ' ')}: {cls.local_path}\n" \ - + f"{'remote storage path'.rjust(20, ' ')}: {cls.remote_path}\n" \ - + f"{'remote ip'.rjust(20, ' ')}: {cls.remote_ip}\n" \ - + f"{'remote port'.rjust(20, ' ')}: {cls.remote_port}\n" \ - + f"{'device name'.rjust(20, ' ')}: {cls.device_name}\n" \ - + f"{'connect type'.rjust(20, ' ')}: {cls.tmode}\n" \ - + f"{'hdc head'.rjust(20, ' ')}: {cls.hdc_head}\n" \ - + f"{'changed testcase'.rjust(20, ' ')}: {cls.changed_testcase}\n" \ - + f"{'testcase path'.rjust(20, ' ')}: {cls.testcase_path}\n" \ - + f"{'loaded testcase'.rjust(20, ' ')}: {cls.loaded_testcase}\n" - print(info) - - - @classmethod - def tconn_tcp(cls): - res = subprocess.check_output(f"{cls.hdc_exe} tconn {cls.remote_ip}:{cls.remote_port}".split()).decode() - if "Connect OK" in res: - return True - else: - return False - - - @classmethod - def set_options(cls): - if opt := input(f"Default hdc execution? [{cls.hdc_exe}]\n").strip(): - cls.hdc_exe = opt - if opt := input(f"Default local storage path? [{cls.local_path}]\n").strip(): - cls.local_path = opt - if opt := input(f"Default remote storage path? [{cls.remote_path}]\n").strip(): - cls.remote_path = opt - if opt := input(f"Default remote ip? [{cls.remote_ip}]\n").strip(): - cls.remote_ip = opt - if opt := input(f"Default remote port? [{cls.remote_port}]\n").strip(): - cls.remote_port = int(opt) - if opt := input(f"Default device name? [{cls.device_name}], opts: {cls.targets}\n").strip(): - cls.device_name = opt - if opt := input(f"Default connect type? [{cls.tmode}], opt: [usb, tcp]\n").strip(): - cls.tmode = opt - if cls.tmode == "usb": - ret = cls.get_device() - if ret: - print("USB device detected.") - elif cls.tconn_tcp(): - cls.hdc_head = f"{cls.hdc_exe} -t {cls.remote_ip}:{cls.remote_port}" - else: - print(f"tconn {cls.remote_ip}:{cls.remote_port} failed") - return False - return True - - - @classmethod - def change_testcase(cls): - if opt := input(f"Change default testcase?(Y/n) [{cls.changed_testcase}]\n").strip(): - cls.changed_testcase = opt - if opt == "n": - return False - if opt := input(f"Use default testcase path?(Y/n) [{cls.testcase_path}]\n").strip(): - cls.testcase_path = os.path.join(opt) - cls.print_options() - return True - - - @classmethod - def load_testcase(cls): - print("this fuction will coming soon.") - return False - - @classmethod - def get_version(cls): - version = f"v1.0.4a" - return version - - -def pytest_run(args): - file_list = [] - file_list.append("entry-default-signed-debug.hap") - file_list.append("libA_v10001.hsp") - file_list.append("libB_v10001.hsp") - for file in file_list: - if not os.path.exists(os.path.join(GP.local_path, file)): - print(f"No {file} File!") - print("请将package.zip中的安装包文件解压到当前脚本resource目录中,操作完成该步骤后重新执行脚本。") - print("Please unzip package.zip to resource directory, please rerun after operation.") - input("[ENTER]") - return - gen_package_dir() - start_time = time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(time.time())) - if args.count is not None: - for i in range(args.count): - print(f"------------The {i}/{args.count} Test-------------") - timestamp = time.time() - pytest_args = [ - '--verbose', args.verbose, - '--report=report.html', - '--title=HDC Test Report 'f"{GP.get_version()}", - '--tester=tester001', - '--template=1', - '--desc='f"{args.verbose}:{args.desc}" - ] - pytest.main(pytest_args) - end_time = time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(time.time())) - report_time = time.strftime('%Y-%m-%d_%H_%M_%S', time.localtime(time.time())) - report_dir = os.path.join(os.getcwd(), "reports") - report_file = os.path.join(report_dir, f"{report_time}report.html") - print(f"Test over, the script version is {GP.get_version()}," - f" start at {start_time}, end at {end_time} \n" - f"=======>The device hdcd ROM size is {GP.hdcd_rom}.\n" - f"=======>{report_file} is saved. \n" - ) - input("=======>press [Enter] key to Show logs.") - - -def rmdir(path): - try: - if sys.platform == "win32": - if os.path.isfile(path): - os.remove(path) - else: - shutil.rmtree(path) - else: - subprocess.call(f"rm -rf {path}".split()) - except OSError: - print(f"Error: {path} : cannot remove") - pass - - -def get_local_path(path): - return os.path.join(GP.local_path, path) - - -def get_remote_path(path): - return f"{GP.remote_path}/{path}" - - -def get_local_md5(local): - md5_hash = hashlib.md5() - with open(local, "rb") as f: - for byte_block in iter(lambda: f.read(4096), b""): - md5_hash.update(byte_block) - return md5_hash.hexdigest() - - -def check_shell_any_device(cmd, pattern=None, fetch=False): - print(f"\nexecuting command: {cmd}") - if pattern: # check output valid - print("pattern case") - output = subprocess.check_output(cmd.split()).decode() - res = pattern in output - print(f"--> output: {output}") - print(f"--> pattern [{pattern}] {'FOUND' if res else 'NOT FOUND'} in output") - return res, output - elif fetch: - output = subprocess.check_output(cmd.split()).decode() - print(f"--> output: {output}") - return True, output - else: # check cmd run successfully - print("other case") - return subprocess.check_call(cmd.split()) == 0, "" - - -def check_shell(cmd, pattern=None, fetch=False, head=None): - if head is None: - head = GP.hdc_head - cmd = f"{head} {cmd}" - print(f"\nexecuting command: {cmd}") - if pattern: # check output valid - output = subprocess.check_output(cmd.split()).decode() - res = pattern in output - print(f"--> output: {output}") - print(f"--> pattern [{pattern}] {'FOUND' if res else 'NOT FOUND'} in output") - return res - elif fetch: - output = subprocess.check_output(cmd.split()).decode() - print(f"--> output: {output}") - return output - else: # check cmd run successfully - return subprocess.check_call(cmd.split()) == 0 - - -def get_shell_result(cmd, pattern=None, fetch=False): - cmd = f"{GP.hdc_head} {cmd}" - print(f"\nexecuting command: {cmd}") - return subprocess.check_output(cmd.split()).decode() - - -def check_rate(cmd, expected_rate): - send_result = get_shell_result(cmd) - rate = float(send_result.split("rate:")[1].split("kB/s")[0]) - return rate > expected_rate - - -def check_dir(local, remote, is_single_dir=False): - def _get_md5sum(remote, is_single_dir=False): - if is_single_dir: - cmd = f"{GP.hdc_head} shell md5sum {remote}/*" - else: - cmd = f'{GP.hdc_head} shell find {remote} -type f -exec md5sum {{}} \;' - result = subprocess.check_output(cmd.split()).decode() - return result - - def _calculate_md5(file_path): - md5 = hashlib.md5() - try: - with open(file_path, 'rb') as f: - for chunk in iter(lambda: f.read(4096), b""): - md5.update(chunk) - return md5.hexdigest() - except PermissionError: - return "PermissionError" - except FileNotFoundError: - return "FileNotFoundError" - print("remote:" + remote) - output = _get_md5sum(remote) - print(output) - - result = 1 - for line in output.splitlines(): - if len(line) < 32: # length of MD5 - continue - expected_md5, file_name = line.split()[:2] - if is_single_dir: - file_name = file_name.replace(f"{remote}", "") - elif GP.remote_path in remote: - file_name = file_name.split(GP.remote_dir_path)[1].replace("/", "\\") - else: - file_name = file_name.split(remote)[1].replace("/", "\\") - file_path = os.path.join(os.getcwd(), GP.local_path) + file_name # 构建完整的文件路径 - if is_single_dir: - file_path = os.path.join(os.getcwd(), local) + file_name - print(file_path) - actual_md5 = _calculate_md5(file_path) - print(f"Expected: {expected_md5}") - print(f"Actual: {actual_md5}") - print(f"MD5 matched {file_name}") - if actual_md5 != expected_md5: - print(f"[Fail]MD5 mismatch for {file_name}") - result *= 0 - - return (result == 1) - - -def _check_file(local, remote, head=None): - if head is None: - head = GP.hdc_head - if remote.startswith("/proc"): - local_size = os.path.getsize(local) - if local_size > 0: - return True - else: - return False - else: - cmd = f"shell md5sum {remote}" - local_md5 = get_local_md5(local) - return check_shell(cmd, local_md5, head=head) - - -def _check_app_installed(bundle, is_shared=False): - dump = "dump-shared" if is_shared else "dump" - cmd = f"shell bm {dump} -a" - return check_shell(cmd, bundle) - - -def check_hdc_targets(): - cmd = f"{GP.hdc_head} list targets" - print(GP.device_name) - return check_shell(cmd, GP.device_name) - - -def check_file_send(local, remote): - local_path = os.path.join(GP.local_path, local) - remote_path = f"{GP.remote_path}/{remote}" - cmd = f"file send {local_path} {remote_path}" - return check_shell(cmd) and _check_file(local_path, remote_path) - - -def check_file_recv(remote, local): - local_path = os.path.join(GP.local_path, local) - remote_path = f"{GP.remote_path}/{remote}" - cmd = f"file recv {remote_path} {local_path}" - return check_shell(cmd) and _check_file(local_path, remote_path) - - -def check_app_install(app, bundle, args=""): - app = os.path.join(GP.local_path, app) - install_cmd = f"install {args} {app}" - if (args == "-s" and app.endswith(".hap")) or (args == "" and app.endswith(".hsp")): - return check_shell(install_cmd, "failed to install bundle") - else: - return check_shell(install_cmd, "successfully") and _check_app_installed(bundle, "s" in args) - - -def check_app_uninstall(bundle, args=""): - uninstall_cmd = f"uninstall {args} {bundle}" - return check_shell(uninstall_cmd, "successfully") and not _check_app_installed(bundle, "s" in args) - - -def check_app_install_multi(tables, args=""): - apps = [] - bundles = [] - for app, bundle in tables.items() : - app = os.path.join(GP.local_path, app) - apps.append(app) - bundles.append(bundle) - - apps_str = " ".join(apps) - install_cmd = f"install {args} {apps_str}" - - if ((args == "-s" and re.search(".hap", apps_str)) or (re.search(".hsp", apps_str) and re.search(".hap", apps_str)) - or (args == "" and 0 == apps_str.count(".hap"))): - if not check_shell(install_cmd, "failed to install bundle"): - return False - else: - if not check_shell(install_cmd, "successfully"): - return False - - for bundle in bundles: - if not _check_app_installed(bundle, "s" in args): - return False - - return True - - -def check_app_uninstall_multi(tables, args=""): - for app, bundle in tables.items() : - if not check_app_uninstall(bundle, args): - return False - - return True - - -def check_hdc_cmd(cmd, pattern=None, head=None, is_single_dir=True, **args): - if head is None: - head = GP.hdc_head - if cmd.startswith("file"): - if not check_shell(cmd, "FileTransfer finish", head=head): - return False - if cmd.startswith("file send"): - local, remote = cmd.split()[-2:] - if remote[-1] == '/' or remote[-1] == '\\': - remote = f"{remote}{os.path.basename(local)}" - else: - remote, local = cmd.split()[-2:] - if local[-1] == '/' or local[-1] == '\\': - local = f"{local}{os.path.basename(remote)}" - if "-b" in cmd: - mnt_debug_path = "mnt/debug/100/debug_hap/" - remote = f"{mnt_debug_path}/{GP.debug_app}/{remote}" - if os.path.isfile(local): - return _check_file(local, remote, head=head) - else: - return check_dir(local, remote, is_single_dir=is_single_dir) - elif cmd.startswith("install"): - bundle = args.get("bundle", "invalid") - opt = " ".join(cmd.split()[1:-1]) - return check_shell(cmd, "successfully") and _check_app_installed(bundle, "s" in opt) - - elif cmd.startswith("uninstall"): - bundle = cmd.split()[-1] - opt = " ".join(cmd.split()[1:-1]) - return check_shell(cmd, "successfully") and not _check_app_installed(bundle, "s" in opt) - - else: - return check_shell(cmd, pattern, head=head, **args) - - -def check_soft_local(local_source, local_soft, remote): - cmd = f"file send {local_soft} {remote}" - if not check_shell(cmd, "FileTransfer finish"): - return False - return _check_file(local_source, remote) - - -def check_soft_remote(remote_source, remote_soft, local_recv): - check_hdc_cmd(f"shell ln -s {remote_source} {remote_soft}") - cmd = f"file recv {remote_soft} {local_recv}" - if not check_shell(cmd, "FileTransfer finish"): - return False - return _check_file(local_recv, get_remote_path(remote_source)) - - -def switch_usb(): - res = check_hdc_cmd("tmode usb") - time.sleep(3) - if res: - GP.hdc_head = f"{GP.hdc_exe} -t {GP.device_name}" - return res - - -def copy_file(src, dst): - try: - shutil.copy2(src, dst) - print(f"File copied successfully from {src} to {dst}") - except IOError as e: - print(f"Unable to copy file. {e}") - except Exception as e: - print(f"Unexpected error: {e}") - - -def switch_tcp(): - if not GP.remote_ip: # skip tcp check - print("!!! remote_ip is none, skip tcp check !!!") - return True - if GP.remote_ip == "auto": - ipconf = check_hdc_cmd("shell \"ifconfig -a | grep inet | grep -v 127.0.0.1 | grep -v inet6\"", fetch=True) - if not ipconf: - print("!!! device ip not found, skip tcp check !!!") - return True - GP.remote_ip = ipconf.split(":")[1].split()[0] - print(f"fetch remote ip: {GP.remote_ip}") - ret = check_hdc_cmd(f"tmode port {GP.remote_port}") - if ret: - time.sleep(3) - res = check_hdc_cmd(f"tconn {GP.remote_ip}:{GP.remote_port}", "Connect OK") - if res: - GP.hdc_head = f"{GP.hdc_exe} -t {GP.remote_ip}:{GP.remote_port}" - return res - - -def select_cmd(): - msg = "1) Proceed tester\n" \ - + "2) Customize tester\n" \ - + "3) Setup files for transfer\n" \ - + "4) Load custom testcase(default unused) \n" \ - + "5) Exit\n" \ - + ">> " - - while True: - opt = input(msg).strip() - if len(opt) == 1 and '1' <= opt <= '5': - return opt - - -def gen_file(path, size): - index = 0 - path = os.path.abspath(path) - fd = os.open(path, os.O_WRONLY | os.O_CREAT, 0o755) - - while index < size: - os.write(fd, os.urandom(1024)) - index += 1024 - os.close(fd) - - -def gen_zero_file(path, size): - fd = os.open(path, os.O_WRONLY | os.O_CREAT, 0o755) - os.write(fd, b'0' * size) - os.close(fd) - - -def create_file_with_size(path, size): - fd = os.open(path, os.O_WRONLY | os.O_CREAT, 0o755) - os.write(fd, b'\0' * size) - os.close(fd) - - -def gen_file_set(): - print("generating empty file ...") - gen_file(os.path.join(GP.local_path, "empty"), 0) - - print("generating small file ...") - gen_file(os.path.join(GP.local_path, "small"), 102400) - - print("generating medium file ...") - gen_file(os.path.join(GP.local_path, "medium"), 200 * 1024 ** 2) - - print("generating large file ...") - gen_file(os.path.join(GP.local_path, "large"), 2 * 1024 ** 3) - - print("generating soft link ...") - try: - os.symlink("small", os.path.join(GP.local_path, "soft_small")) - except FileExistsError: - print("soft_small already exists") - - print("generating text file ...") - gen_zero_file(os.path.join(GP.local_path, "word_100M.txt"), 100 * 1024 ** 2) - - print("generating package dir ...") - if not os.path.exists(os.path.join(GP.local_path, "package")): - os.mkdir(os.path.join(GP.local_path, "package")) - for i in range(1, 6): - gen_file(os.path.join(GP.local_path, "package", f"fake.hap.{i}"), 20 * 1024 ** 2) - - print("generating deep dir ...") - deepth = 4 - deep_path = os.path.join(GP.local_path, "deep_dir") - if not os.path.exists(deep_path): - os.mkdir(deep_path) - for deep in range(deepth): - deep_path = os.path.join(deep_path, f"deep_dir{deep}") - if not os.path.exists(deep_path): - os.mkdir(deep_path) - gen_file(os.path.join(deep_path, "deep"), 102400) - - print("generating dir with file ...") - dir_path = os.path.join(GP.local_path, "problem_dir") - rmdir(dir_path) - os.mkdir(dir_path) - gen_file(os.path.join(dir_path, "small2"), 102400) - - fuzz_count = 47 # 47 is the count that circulated the file transfer - data_unit = 1024 # 1024 is the size that circulated the file transfer - data_extra = 936 # 936 is the size that cased the extra file transfer - for i in range(fuzz_count): - create_file_with_size( - os.path.join( - dir_path, f"file_{i * data_unit+data_extra}.dat" - ), i * data_unit + data_extra - ) - - print("generating empty dir ...") - dir_path = os.path.join(GP.local_path, "empty_dir") - rmdir(dir_path) - os.mkdir(dir_path) - - print("generating version file ...") - gen_file(os.path.join(GP.local_path, GP.get_version()), 0) - - -def gen_package_dir(): - print("generating app dir ...") - dir_path = os.path.join(GP.local_path, "app_dir") - rmdir(dir_path) - os.mkdir(dir_path) - app = os.path.join(GP.local_path, "entry-default-signed-debug.hap") - dst_dir = os.path.join(GP.local_path, "app_dir") - if not os.path.exists(app): - print(f"Source file {app} does not exist.") - else: - copy_file(app, dst_dir) - - -def prepare_source(): - if os.path.exists(os.path.join(GP.local_path, GP.get_version())): - print(f"hdc test version is {GP.get_version}, check ok, skip prepare.") - return - print(f"in prepare {GP.local_path},wait for 2 mins.") - current_path = os.getcwd() - - if os.path.exists(GP.local_path): - #打开local_path遍历其中的文件,删除hap hsp以外的所有文件 - for file in os.listdir(GP.local_path): - if file.endswith(".hap") or file.endswith(".hsp"): - continue - file_path = os.path.join(GP.local_path, file) - rmdir(file_path) - else: - os.mkdir(GP.local_path) - - gen_file_set() - - -def add_prepare_source(): - deep_path = os.path.join(GP.local_path, "deep_test_dir") - print("generating deep test dir ...") - absolute_path = os.path.abspath(__file__) - deepth = (255 - 9 - len(absolute_path)) % 14 - os.mkdir(deep_path) - for deep in range(deepth): - deep_path = os.path.join(deep_path, f"deep_test_dir{deep}") - os.mkdir(deep_path) - gen_file(os.path.join(deep_path, "deep_test"), 102400) - - recv_dir = os.path.join(GP.local_path, "recv_test_dir") - print("generating recv test dir ...") - os.mkdir(recv_dir) - - -def update_source(): - deep_path = os.path.join(GP.local_path, "deep_test_dir") - if not os.path.exists(deep_path): - print("generating deep test dir ...") - absolute_path = os.path.abspath(__file__) - deepth = (255 - 9 - len(absolute_path)) % 14 - os.mkdir(deep_path) - for deep in range(deepth): - deep_path = os.path.join(deep_path, f"deep_test_dir{deep}") - os.mkdir(deep_path) - gen_file(os.path.join(deep_path, "deep_test"), 102400) - - recv_dir = os.path.join(GP.local_path, "recv_test_dir") - if not os.path.exists(recv_dir): - print("generating recv test dir ...") - os.mkdir(recv_dir) - - -def setup_tester(): - while True: - GP.print_options() - opt = int(select_cmd()) - if opt == 1: - return True - elif opt == 2: - if not GP.set_options(): - return False - GP.dump() - elif opt == 3: - prepare_source() - elif opt == 4: - if not GP.load_testcase(): - return False - elif opt == 5: - return False - else: - return False - - -def load_testcase(): - if not GP.load_testcase: - print("load testcase failed") - return False - print("load testcase success") - return True - - -def check_library_installation(library_name): - try: - pkg_resources.get_distribution(library_name) - return 0 - except pkg_resources.DistributionNotFound: - print(f"\n\n{library_name} is not installed.\n\n") - print(f"try to use command below:") - print(f"pip install {library_name}") - return 1 - - -def check_subprocess_cmd(cmd, process_num, timeout): - - for i in range(process_num): - p = subprocess.Popen(cmd.split()) - try: - p.wait(timeout=5) - except subprocess.TimeoutExpired: - p.kill() - - -def check_process_mixed(process_num, timeout, local, remote): - multi_num = process_num - list_send = [] - list_recv = [] - sizes = {"small", "medium", "empty"} - for i in range(multi_num): - for size in sizes: - cmd_send = f"file send {get_local_path(f'{size}')} {get_remote_path(f'it_{size}_mix_{i}')}" - cmd_recv = f"file recv {get_remote_path(f'it_{size}_mix_{i}')} {get_local_path(f'recv_{size}_mix_{i}')}" - list_send.append(Process(target=check_hdc_cmd, args=(cmd_send, ))) - list_recv.append(Process(target=check_hdc_cmd, args=(cmd_recv, ))) - logging.info(f"RESULT:{cmd_send}") # 打印命令的输出 - for send in list_send: - wait_time = random.uniform(0, 1) - send.start() - time.sleep(wait_time) - for send in list_send: - send.join() - - for recv in list_recv: - wait_time = random.uniform(0, 1) - recv.start() - time.sleep(wait_time) - for recv in list_recv: - recv.join() - wait_time = random.uniform(0, 1) - time.sleep(wait_time) - - -def execute_lines_in_file(file_path): - if not os.path.exists(file_path): - flags = os.O_WRONLY | os.O_CREAT | os.O_EXCL - modes = stat.S_IWUSR | stat.S_IRUSR - with os.fdopen(os.open(file_path, flags, modes), 'w') as file: - file.write("1,hdc shell ls") - with open(file_path, 'r') as file: - lines = file.readlines() - for line in lines: - test_time = line.split(',')[0] - test_cmd = line.split(',')[1] - pattern = r"^hdc" - match = re.search(pattern, test_cmd) - if match: - result = test_cmd.replace(match.group(0), "").lstrip() - test_cmd = f"{GP.hdc_head} {result}" - - for i in range(int(test_time)): - logging.info(f"THE {i+1}/{test_time} TEST,COMMAND IS:{test_cmd}") - output = subprocess.check_output(test_cmd.split()).decode() - logging.info(f"RESULT:{output}") # 打印命令的输出 - - -def make_multiprocess_file(local, remote, mode, num, task_type): - if num < 1: - return False - if task_type == "file": - if mode == "send" : - file_list = [f"{GP.hdc_head} file send {local} {remote}_{i}" for i in range(num)] - elif mode == "recv": - file_list = [f"{GP.hdc_head} file recv {remote}_{i} {local}_{i}" for i in range(num)] - else: - return False - if task_type == "dir": - if mode == "send" : - file_list = [f"{GP.hdc_head} file send {local} {remote}" for _ in range(num)] - elif mode == "recv": - file_list = [f"{GP.hdc_head} file recv {remote} {local}" for _ in range(num)] - else: - return False - print(file_list[0]) - p_list = [subprocess.Popen(cmd.split(), stdout=subprocess.PIPE, stderr=subprocess.PIPE) for cmd in file_list] - print(f"{mode} target {num} start") - while(len(p_list)): - for p in p_list: - if p.poll() is not None: - stdout, stderr = p.communicate(timeout=512) # timeout wait 512s - if stderr: - print(f"{stderr.decode()}") - if stdout: - print(f"{stdout.decode()}") - if stdout.decode().find("FileTransfer finish") == -1: - return False - p_list.remove(p) - res = 1 - if task_type == "file": - for i in range(num): - if mode == "send": - if _check_file(local, f"{remote}_{i}"): - res *= 1 - else: - res *= 0 - elif mode == "recv": - if _check_file(f"{local}_{i}", f"{remote}_{i}"): - res *= 1 - else: - res *= 0 - if task_type == "dir": - for _ in range(num): - if mode == "send": - end_of_file_name = os.path.basename(local) - if check_dir(local, f"{remote}/{end_of_file_name}", is_single_dir=True): - res *= 1 - else: - res *= 0 - elif mode == "recv": - end_of_file_name = os.path.basename(remote) - local = os.path.join(local, end_of_file_name) - if check_dir(f"{local}", f"{remote}", is_single_dir=True): - res *= 1 - else: - res *= 0 - return res == 1 - - -def hdc_get_key(cmd): - test_cmd = f"{GP.hdc_head} {cmd}" - result = subprocess.check_output(test_cmd.split()).decode() - return result - - -def start_subprocess_cmd(cmd, num, assert_out): - if num < 1: - return False - cmd_list = [f"{GP.hdc_head} {cmd}" for _ in range(num)] - p_list = [subprocess.Popen(cmd.split(), stdout=subprocess.PIPE, stderr=subprocess.PIPE) for cmd in cmd_list] - logging.info(f"{cmd} target {num} start") - while(len(p_list)): - for p in p_list: - if p.poll() is not None: - stdout, stderr = p.communicate(timeout=512) - if stderr: - logging.error(f"{stderr.decode()}") - if stdout: - logging.info(f"{stdout.decode()}") - if assert_out is not None and stdout.decode().find(assert_out) == -1: - return False - p_list.remove(p) - return True - - -def check_hdc_version(cmd, version): - - def _convert_version_to_hex(_version): - parts = _version.split("Ver: ")[1].split('.') - hex_version = ''.join(parts) - return int(hex_version, 16) - - expected_version = _convert_version_to_hex(version) - cmd = f"{GP.hdc_head} -v" - print(f"\nexecuting command: {cmd}") - if version is not None: # check output valid - output = subprocess.check_output(cmd.split()).decode().replace("\r", "").replace("\n", "") - real_version = _convert_version_to_hex(output) - print(f"--> output: {output}") - print(f"--> your local [{version}] is" - f" {'' if expected_version <= real_version else 'too old to'} fit the version [{output}]" - ) - return expected_version <= real_version - - -def check_cmd_time(cmd, pattern, duration, times): - if times < 1: - print("times should be bigger than 0.") - return False - if pattern is None: - fetchable = True - else: - fetchable = False - start_time = time.time() * 1000 - print(f"{cmd} start {start_time}") - res = [] - for i in range(times): - start_in = time.time() * 1000 - if pattern is None: - subprocess.check_output(f"{GP.hdc_head} {cmd}".split()) - else: - assert check_shell(cmd, pattern, fetch=fetchable) - start_out = time.time() * 1000 - res.append(start_out - start_in) - - # 计算最大值、最小值和中位数 - max_value = max(res) - min_value = min(res) - median_value = sorted(res)[len(res) // 2] - - print(f"{GP.hdc_head} {cmd}耗时最大值:{max_value}") - print(f"{GP.hdc_head} {cmd}耗时最小值:{min_value}") - print(f"{GP.hdc_head} {cmd}耗时中位数:{median_value}") - - end_time = time.time() * 1000 - - try: - timecost = int(end_time - start_time) / times - print(f"{GP.hdc_head} {cmd}耗时平均值 {timecost}") - except ZeroDivisionError: - print(f"除数为0") - - if duration is None: - duration = 150 * 1.2 - # 150ms is baseline timecost for hdc shell xxx cmd, 20% can be upper maybe system status - return timecost < duration - - -def check_rom(baseline): - - def _try_get_size(message): - try: - size = int(message.split('\t')[0]) - except ValueError: - size = -9999 * 1024 # error size - print(f"try get size value error, from {message}") - return size - - if baseline is None: - baseline = 2200 - # 2200KB is the baseline of hdcd and libhdc.dylib.so size all together - cmd_hdcd = f"{GP.hdc_head} shell du system/bin/hdcd" - result_hdcd = subprocess.check_output(cmd_hdcd.split()).decode() - hdcd_size = _try_get_size(result_hdcd) - cmd_libhdc = f"{GP.hdc_head} shell du system/lib/libhdc.dylib.so" - result_libhdc = subprocess.check_output(cmd_libhdc.split()).decode() - if "directory" in result_libhdc: - cmd_libhdc64 = f"{GP.hdc_head} shell du system/lib64/libhdc.dylib.so" - result_libhdc64 = subprocess.check_output(cmd_libhdc64.split()).decode() - if "directory" in result_libhdc64: - libhdc_size = 0 - else: - libhdc_size = _try_get_size(result_libhdc64) - else: - libhdc_size = _try_get_size(result_libhdc) - all_size = hdcd_size + libhdc_size - GP.hdcd_rom = all_size - if all_size < 0: - GP.hdcd_rom = "error" - return False - else: - GP.hdcd_rom = f"{all_size} KB" - if all_size > baseline: - print(f"rom size is {all_size}, overlimit baseline {baseline}") - return False - else: - print(f"rom size is {all_size}, underlimit baseline {baseline}") - return True - - -def run_command_with_timeout(command, timeout): - try: - result = subprocess.run(command, check=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, timeout=timeout) - return result.stdout.decode(), result.stderr.decode() - except subprocess.TimeoutExpired: - return None, "Command timed out" - except subprocess.CalledProcessError as e: - return None, e.stderr.decode() - - -def check_cmd_block(command, pattern, timeout=600): - # 启动子进程 - process = subprocess.Popen(command.split(), stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True) - - # 用于存储子进程的输出 - output = "" - - try: - # 读取子进程的输出 - output, _ = process.communicate(timeout=timeout) - except subprocess.TimeoutExpired: - process.terminate() - process.kill() - output, _ = process.communicate(timeout=timeout) - - print(f"--> output: {output}") - if pattern in output: - return True - else: - return False +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +# Copyright (C) 2021 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. +# 运行环境: python 3.10+, pytest + +import hashlib +import json +import os +import re +import shutil +import subprocess +import sys +import time +import functools + +import pytest +import importlib + + +class GP(object): + """ Global Parameters + + customize here !!! + """ + hdc_exe = "hdc" + local_path = "resource" + remote_path = "data/local/tmp" + remote_dir_path = "data/local/tmp/it_send_dir" + remote_ip = "auto" + remote_port = 8710 + hdc_head = "hdc" + device_name = "" + targets = [] + tmode = "usb" + changed_testcase = "n" + testcase_path = "ts_windows.csv" + loaded_testcase = 0 + hdcd_rom = "not checked" + debug_app = "com.example.myapplication" + + @classmethod + def init(cls): + if os.path.exists(".hdctester.conf"): + cls.load() + cls.start_host() + cls.list_targets() + else: + cls.set_options() + cls.print_options() + cls.start_host() + cls.dump() + return + + + @classmethod + def start_host(cls): + cmd = f"{cls.hdc_exe} start" + res = subprocess.call(cmd.split()) + return res + + @classmethod + def list_targets(cls): + try: + targets = subprocess.check_output(f"{cls.hdc_exe} list targets".split()).split() + except (OSError, IndexError): + targets = [b"failed to auto detect device"] + cls.targets = [targets[0].decode()] + return False + cls.targets = [t.decode() for t in targets] + return True + + + @classmethod + def get_device(cls): + cls.start_host() + cls.list_targets() + if len(cls.targets) > 1: + print("Multiple device detected, please select one:") + for i, t in enumerate(cls.targets): + print(f"{i+1}. {t}") + print("input the nums of the device above:") + cls.device_name = cls.targets[int(input()) - 1] + else: + cls.device_name = cls.targets[0] + if cls.device_name == "failed to auto detect device": + print("No device detected, please check your device connection") + return False + elif cls.device_name == "[empty]": + print("No hdc device detected.") + return False + cls.hdc_head = f"{cls.hdc_exe} -t {cls.device_name}" + return True + + + @classmethod + def dump(cls): + try: + os.remove(".hdctester.conf") + except OSError: + pass + content = filter( + lambda k: not k[0].startswith("__") and not isinstance(k[1], classmethod), cls.__dict__.items()) + json_str = json.dumps(dict(content)) + fd = os.open(".hdctester.conf", os.O_WRONLY | os.O_CREAT, 0o755) + os.write(fd, json_str.encode()) + os.close(fd) + return True + + + @classmethod + def load(cls): + if not os.path.exists(".hdctester.conf"): + raise ConfigFileNotFoundException("No config file found, please run command [python prepare.py]") + with open(".hdctester.conf") as f: + content = json.load(f) + cls.hdc_exe = content.get("hdc_exe") + cls.local_path = content.get("local_path") + cls.remote_path = content.get("remote_path") + cls.remote_ip = content.get("remote_ip") + cls.hdc_head = content.get("hdc_head") + cls.tmode = content.get("tmode") + cls.device_name = content.get("device_name") + cls.changed_testcase = content.get("changed_testcase") + cls.testcase_path = content.get("testcase_path") + cls.loaded_testcase = content.get("load_testcase") + return True + + + @classmethod + def print_options(cls): + info = "HDC Tester Default Options: \n\n" \ + + f"{'hdc execution'.rjust(20, ' ')}: {cls.hdc_exe}\n" \ + + f"{'local storage path'.rjust(20, ' ')}: {cls.local_path}\n" \ + + f"{'remote storage path'.rjust(20, ' ')}: {cls.remote_path}\n" \ + + f"{'remote ip'.rjust(20, ' ')}: {cls.remote_ip}\n" \ + + f"{'remote port'.rjust(20, ' ')}: {cls.remote_port}\n" \ + + f"{'device name'.rjust(20, ' ')}: {cls.device_name}\n" \ + + f"{'connect type'.rjust(20, ' ')}: {cls.tmode}\n" \ + + f"{'hdc head'.rjust(20, ' ')}: {cls.hdc_head}\n" \ + + f"{'changed testcase'.rjust(20, ' ')}: {cls.changed_testcase}\n" \ + + f"{'testcase path'.rjust(20, ' ')}: {cls.testcase_path}\n" \ + + f"{'loaded testcase'.rjust(20, ' ')}: {cls.loaded_testcase}\n" + print(info) + + + @classmethod + def tconn_tcp(cls): + res = subprocess.check_output(f"{cls.hdc_exe} tconn {cls.remote_ip}:{cls.remote_port}".split()).decode() + if "Connect OK" in res: + return True + else: + return False + + + @classmethod + def set_options(cls): + if opt := input(f"Default hdc execution? [{cls.hdc_exe}]\n").strip(): + cls.hdc_exe = opt + if opt := input(f"Default local storage path? [{cls.local_path}]\n").strip(): + cls.local_path = opt + if opt := input(f"Default remote storage path? [{cls.remote_path}]\n").strip(): + cls.remote_path = opt + if opt := input(f"Default remote ip? [{cls.remote_ip}]\n").strip(): + cls.remote_ip = opt + if opt := input(f"Default remote port? [{cls.remote_port}]\n").strip(): + cls.remote_port = int(opt) + if opt := input(f"Default device name? [{cls.device_name}], opts: {cls.targets}\n").strip(): + cls.device_name = opt + if opt := input(f"Default connect type? [{cls.tmode}], opt: [usb, tcp]\n").strip(): + cls.tmode = opt + if cls.tmode == "usb": + ret = cls.get_device() + if ret: + print("USB device detected.") + elif cls.tconn_tcp(): + cls.hdc_head = f"{cls.hdc_exe} -t {cls.remote_ip}:{cls.remote_port}" + else: + print(f"tconn {cls.remote_ip}:{cls.remote_port} failed") + return False + return True + + + @classmethod + def change_testcase(cls): + if opt := input(f"Change default testcase?(Y/n) [{cls.changed_testcase}]\n").strip(): + cls.changed_testcase = opt + if opt == "n": + return False + if opt := input(f"Use default testcase path?(Y/n) [{cls.testcase_path}]\n").strip(): + cls.testcase_path = os.path.join(opt) + cls.print_options() + return True + + + @classmethod + def load_testcase(cls): + print("this fuction will coming soon.") + return False + + @classmethod + def get_version(cls): + version = f"v1.0.5a" + return version + + +def pytest_run(): + start_time = time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(time.time())) + pytest.main() + end_time = time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(time.time())) + report_time = time.strftime('%Y-%m-%d_%H_%M_%S', time.localtime(time.time())) + report_dir = os.path.join(os.getcwd(), "reports") + report_file = os.path.join(report_dir, f"{report_time}report.html") + print(f"Test over, the script version is {GP.get_version()}," + f" start at {start_time}, end at {end_time} \n" + f"=======>{report_file} is saved. \n" + ) + input("=======>press [Enter] key to Show logs.") + + +def rmdir(path): + try: + if sys.platform == "win32": + if os.path.isfile(path): + os.remove(path) + else: + shutil.rmtree(path) + else: + subprocess.call(f"rm -rf {path}".split()) + except OSError: + print(f"Error: {path} : cannot remove") + pass + + +def get_local_path(path): + return os.path.join(GP.local_path, path) + + +def get_remote_path(path): + return f"{GP.remote_path}/{path}" + + +def get_local_md5(local): + md5_hash = hashlib.md5() + with open(local, "rb") as f: + for byte_block in iter(lambda: f.read(4096), b""): + md5_hash.update(byte_block) + return md5_hash.hexdigest() + + +def check_shell_any_device(cmd, pattern=None, fetch=False): + print(f"\nexecuting command: {cmd}") + if pattern: # check output valid + print("pattern case") + output = subprocess.check_output(cmd.split()).decode() + res = pattern in output + print(f"--> output: {output}") + print(f"--> pattern [{pattern}] {'FOUND' if res else 'NOT FOUND'} in output") + return res, output + elif fetch: + output = subprocess.check_output(cmd.split()).decode() + print(f"--> output: {output}") + return True, output + else: # check cmd run successfully + print("other case") + return subprocess.check_call(cmd.split()) == 0, "" + + +def check_shell(cmd, pattern=None, fetch=False, head=None): + if head is None: + head = GP.hdc_head + cmd = f"{head} {cmd}" + print(f"\nexecuting command: {cmd}") + if pattern: # check output valid + output = subprocess.check_output(cmd.split()).decode() + res = pattern in output + print(f"--> output: {output}") + print(f"--> pattern [{pattern}] {'FOUND' if res else 'NOT FOUND'} in output") + return res + elif fetch: + output = subprocess.check_output(cmd.split()).decode() + print(f"--> output: {output}") + return output + else: # check cmd run successfully + return subprocess.check_call(cmd.split()) == 0 + + +def get_shell_result(cmd, pattern=None, fetch=False): + cmd = f"{GP.hdc_head} {cmd}" + print(f"\nexecuting command: {cmd}") + return subprocess.check_output(cmd.split()).decode() + + +def check_rate(cmd, expected_rate): + send_result = get_shell_result(cmd) + rate = float(send_result.split("rate:")[1].split("kB/s")[0]) + return rate > expected_rate + + +def check_dir(local, remote, is_single_dir=False): + def _get_md5sum(remote, is_single_dir=False): + if is_single_dir: + cmd = f"{GP.hdc_head} shell md5sum {remote}/*" + else: + cmd = f'{GP.hdc_head} shell find {remote} -type f -exec md5sum {{}}' + result = subprocess.check_output(cmd.split()).decode() + return result + + def _calculate_md5(file_path): + md5 = hashlib.md5() + try: + with open(file_path, 'rb') as f: + for chunk in iter(lambda: f.read(4096), b""): + md5.update(chunk) + return md5.hexdigest() + except PermissionError: + return "PermissionError" + except FileNotFoundError: + return "FileNotFoundError" + print("remote:" + remote) + output = _get_md5sum(remote) + print(output) + + result = 1 + for line in output.splitlines(): + if len(line) < 32: # length of MD5 + continue + expected_md5, file_name = line.split()[:2] + if is_single_dir: + file_name = file_name.replace(f"{remote}", "") + elif GP.remote_path in remote: + file_name = file_name.split(GP.remote_dir_path)[1].replace("/", "\\") + else: + file_name = file_name.split(remote)[1].replace("/", "\\") + file_path = os.path.join(os.getcwd(), GP.local_path) + file_name # 构建完整的文件路径 + if is_single_dir: + file_path = os.path.join(os.getcwd(), local) + file_name + print(file_path) + actual_md5 = _calculate_md5(file_path) + print(f"Expected: {expected_md5}") + print(f"Actual: {actual_md5}") + print(f"MD5 matched {file_name}") + if actual_md5 != expected_md5: + print(f"[Fail]MD5 mismatch for {file_name}") + result *= 0 + + return (result == 1) + + +def _check_file(local, remote, head=None): + if head is None: + head = GP.hdc_head + if remote.startswith("/proc"): + local_size = os.path.getsize(local) + if local_size > 0: + return True + else: + return False + else: + cmd = f"shell md5sum {remote}" + local_md5 = get_local_md5(local) + return check_shell(cmd, local_md5, head=head) + + +def _check_app_installed(bundle, is_shared=False): + dump = "dump-shared" if is_shared else "dump" + cmd = f"shell bm {dump} -a" + return check_shell(cmd, bundle) + + +def check_hdc_targets(): + cmd = f"{GP.hdc_head} list targets" + print(GP.device_name) + return check_shell(cmd, GP.device_name) + + +def check_file_send(local, remote): + local_path = os.path.join(GP.local_path, local) + remote_path = f"{GP.remote_path}/{remote}" + cmd = f"file send {local_path} {remote_path}" + return check_shell(cmd) and _check_file(local_path, remote_path) + + +def check_file_recv(remote, local): + local_path = os.path.join(GP.local_path, local) + remote_path = f"{GP.remote_path}/{remote}" + cmd = f"file recv {remote_path} {local_path}" + return check_shell(cmd) and _check_file(local_path, remote_path) + + +def check_app_install(app, bundle, args=""): + app = os.path.join(GP.local_path, app) + install_cmd = f"install {args} {app}" + if (args == "-s" and app.endswith(".hap")) or (args == "" and app.endswith(".hsp")): + return check_shell(install_cmd, "failed to install bundle") + else: + return check_shell(install_cmd, "successfully") and _check_app_installed(bundle, "s" in args) + + +def check_app_uninstall(bundle, args=""): + uninstall_cmd = f"uninstall {args} {bundle}" + return check_shell(uninstall_cmd, "successfully") and not _check_app_installed(bundle, "s" in args) + + +def check_app_install_multi(tables, args=""): + apps = [] + bundles = [] + for app, bundle in tables.items() : + app = os.path.join(GP.local_path, app) + apps.append(app) + bundles.append(bundle) + + apps_str = " ".join(apps) + install_cmd = f"install {args} {apps_str}" + + if ((args == "-s" and re.search(".hap", apps_str)) or (re.search(".hsp", apps_str) and re.search(".hap", apps_str)) + or (args == "" and 0 == apps_str.count(".hap"))): + if not check_shell(install_cmd, "failed to install bundle"): + return False + else: + if not check_shell(install_cmd, "successfully"): + return False + + for bundle in bundles: + if not _check_app_installed(bundle, "s" in args): + return False + + return True + + +def check_app_uninstall_multi(tables, args=""): + for app, bundle in tables.items() : + if not check_app_uninstall(bundle, args): + return False + + return True + + +def check_hdc_cmd(cmd, pattern=None, head=None, is_single_dir=True, **args): + if head is None: + head = GP.hdc_head + if cmd.startswith("file"): + if not check_shell(cmd, "FileTransfer finish", head=head): + return False + if cmd.startswith("file send"): + local, remote = cmd.split()[-2:] + if remote[-1] == '/' or remote[-1] == '\\': + remote = f"{remote}{os.path.basename(local)}" + else: + remote, local = cmd.split()[-2:] + if local[-1] == '/' or local[-1] == '\\': + local = f"{local}{os.path.basename(remote)}" + if "-b" in cmd: + mnt_debug_path = "mnt/debug/100/debug_hap/" + remote = f"{mnt_debug_path}/{GP.debug_app}/{remote}" + if os.path.isfile(local): + return _check_file(local, remote, head=head) + else: + return check_dir(local, remote, is_single_dir=is_single_dir) + elif cmd.startswith("install"): + bundle = args.get("bundle", "invalid") + opt = " ".join(cmd.split()[1:-1]) + return check_shell(cmd, "successfully") and _check_app_installed(bundle, "s" in opt) + + elif cmd.startswith("uninstall"): + bundle = cmd.split()[-1] + opt = " ".join(cmd.split()[1:-1]) + return check_shell(cmd, "successfully") and not _check_app_installed(bundle, "s" in opt) + + else: + return check_shell(cmd, pattern, head=head, **args) + + +def check_soft_local(local_source, local_soft, remote): + cmd = f"file send {local_soft} {remote}" + if not check_shell(cmd, "FileTransfer finish"): + return False + return _check_file(local_source, remote) + + +def check_soft_remote(remote_source, remote_soft, local_recv): + check_hdc_cmd(f"shell ln -s {remote_source} {remote_soft}") + cmd = f"file recv {remote_soft} {local_recv}" + if not check_shell(cmd, "FileTransfer finish"): + return False + return _check_file(local_recv, get_remote_path(remote_source)) + + +def switch_usb(): + res = check_hdc_cmd("tmode usb") + time.sleep(3) + if res: + GP.hdc_head = f"{GP.hdc_exe} -t {GP.device_name}" + return res + + +def copy_file(src, dst): + try: + shutil.copy2(src, dst) + print(f"File copied successfully from {src} to {dst}") + except IOError as e: + print(f"Unable to copy file. {e}") + except Exception as e: + print(f"Unexpected error: {e}") + + +def switch_tcp(): + if not GP.remote_ip: # skip tcp check + print("!!! remote_ip is none, skip tcp check !!!") + return True + if GP.remote_ip == "auto": + ipconf = check_hdc_cmd("shell \"ifconfig -a | grep inet | grep -v 127.0.0.1 | grep -v inet6\"", fetch=True) + if not ipconf: + print("!!! device ip not found, skip tcp check !!!") + return True + GP.remote_ip = ipconf.split(":")[1].split()[0] + print(f"fetch remote ip: {GP.remote_ip}") + ret = check_hdc_cmd(f"tmode port {GP.remote_port}") + if ret: + time.sleep(3) + res = check_hdc_cmd(f"tconn {GP.remote_ip}:{GP.remote_port}", "Connect OK") + if res: + GP.hdc_head = f"{GP.hdc_exe} -t {GP.remote_ip}:{GP.remote_port}" + return res + + +def select_cmd(): + msg = "1) Proceed tester\n" \ + + "2) Customize tester\n" \ + + "3) Setup files for transfer\n" \ + + "4) Load custom testcase(default unused) \n" \ + + "5) Exit\n" \ + + ">> " + + while True: + opt = input(msg).strip() + if len(opt) == 1 and '1' <= opt <= '5': + return opt + + +def gen_file(path, size): + index = 0 + path = os.path.abspath(path) + fd = os.open(path, os.O_WRONLY | os.O_CREAT, 0o755) + + while index < size: + os.write(fd, os.urandom(1024)) + index += 1024 + os.close(fd) + + +def gen_version_file(path): + with open(path, "w") as f: + f.write(GP.get_version()) + + +def gen_zero_file(path, size): + fd = os.open(path, os.O_WRONLY | os.O_CREAT, 0o755) + os.write(fd, b'0' * size) + os.close(fd) + + +def create_file_with_size(path, size): + fd = os.open(path, os.O_WRONLY | os.O_CREAT, 0o755) + os.write(fd, b'\0' * size) + os.close(fd) + + +def gen_soft_link(): + print("generating soft link ...") + try: + os.symlink("small", os.path.join(GP.local_path, "soft_small")) + except FileExistsError: + print("soft_small already exists") + except OSError: + print("生成soft_small失败,需要使用管理员权限用户执行软链接生成") + + +def gen_file_set(): + print("generating empty file ...") + gen_file(os.path.join(GP.local_path, "empty"), 0) + + print("generating small file ...") + gen_file(os.path.join(GP.local_path, "small"), 102400) + + print("generating medium file ...") + gen_file(os.path.join(GP.local_path, "medium"), 200 * 1024 ** 2) + + print("generating large file ...") + gen_file(os.path.join(GP.local_path, "large"), 2 * 1024 ** 3) + + print("generating text file ...") + gen_zero_file(os.path.join(GP.local_path, "word_100M.txt"), 100 * 1024 ** 2) + + gen_soft_link() + print("generating package dir ...") + if not os.path.exists(os.path.join(GP.local_path, "package")): + os.mkdir(os.path.join(GP.local_path, "package")) + for i in range(1, 6): + gen_file(os.path.join(GP.local_path, "package", f"fake.hap.{i}"), 20 * 1024 ** 2) + + print("generating deep dir ...") + deepth = 4 + deep_path = os.path.join(GP.local_path, "deep_dir") + if not os.path.exists(deep_path): + os.mkdir(deep_path) + for deep in range(deepth): + deep_path = os.path.join(deep_path, f"deep_dir{deep}") + if not os.path.exists(deep_path): + os.mkdir(deep_path) + gen_file(os.path.join(deep_path, "deep"), 102400) + + print("generating dir with file ...") + dir_path = os.path.join(GP.local_path, "problem_dir") + rmdir(dir_path) + os.mkdir(dir_path) + gen_file(os.path.join(dir_path, "small2"), 102400) + + fuzz_count = 47 # 47 is the count that circulated the file transfer + data_unit = 1024 # 1024 is the size that circulated the file transfer + data_extra = 936 # 936 is the size that cased the extra file transfer + for i in range(fuzz_count): + create_file_with_size( + os.path.join(dir_path, f"file_{i * data_unit+data_extra}.dat"), i * data_unit + data_extra) + print("generating empty dir ...") + dir_path = os.path.join(GP.local_path, "empty_dir") + rmdir(dir_path) + os.mkdir(dir_path) + print("generating version file ...") + gen_version_file(os.path.join(GP.local_path, "version")) + + +def gen_package_dir(): + print("generating app dir ...") + dir_path = os.path.join(GP.local_path, "app_dir") + if os.path.exists(dir_path): + rmdir(dir_path) + os.mkdir(dir_path) + app = os.path.join(GP.local_path, "AACommand07.hap") + dst_dir = os.path.join(GP.local_path, "app_dir") + if not os.path.exists(app): + print(f"Source file {app} does not exist.") + else: + copy_file(app, dst_dir) + + +def prepare_source(): + version_file = os.path.join(GP.local_path, "version") + if os.path.exists(version_file): + with open(version_file, "r") as f: + version = f.read() + if version == GP.get_version(): + print(f"hdc test version is {GP.get_version()}, check ok, skip prepare.") + return + print(f"in prepare {GP.local_path},wait for 2 mins.") + current_path = os.getcwd() + + if os.path.exists(GP.local_path): + #打开local_path遍历其中的文件,删除hap hsp以外的所有文件 + for file in os.listdir(GP.local_path): + if file.endswith(".hap") or file.endswith(".hsp"): + continue + file_path = os.path.join(GP.local_path, file) + rmdir(file_path) + else: + os.mkdir(GP.local_path) + + gen_file_set() + + +def add_prepare_source(): + deep_path = os.path.join(GP.local_path, "deep_test_dir") + print("generating deep test dir ...") + absolute_path = os.path.abspath(__file__) + deepth = (255 - 9 - len(absolute_path)) % 14 + os.mkdir(deep_path) + for deep in range(deepth): + deep_path = os.path.join(deep_path, f"deep_test_dir{deep}") + os.mkdir(deep_path) + gen_file(os.path.join(deep_path, "deep_test"), 102400) + + recv_dir = os.path.join(GP.local_path, "recv_test_dir") + print("generating recv test dir ...") + os.mkdir(recv_dir) + + +def update_source(): + deep_path = os.path.join(GP.local_path, "deep_test_dir") + if not os.path.exists(deep_path): + print("generating deep test dir ...") + absolute_path = os.path.abspath(__file__) + deepth = (255 - 9 - len(absolute_path)) % 14 + os.mkdir(deep_path) + for deep in range(deepth): + deep_path = os.path.join(deep_path, f"deep_test_dir{deep}") + os.mkdir(deep_path) + gen_file(os.path.join(deep_path, "deep_test"), 102400) + + recv_dir = os.path.join(GP.local_path, "recv_test_dir") + if not os.path.exists(recv_dir): + print("generating recv test dir ...") + os.mkdir(recv_dir) + + +def load_testcase(): + if not GP.load_testcase: + print("load testcase failed") + return False + print("load testcase success") + return True + + +def check_library_installation(library_name): + try: + importlib.metadata.version(library_name) + return 0 + except importlib.metadata.PackageNotFoundError: + print(f"\n\n{library_name} is not installed.\n\n") + print(f"try to use command below:") + print(f"pip install {library_name}") + return 1 + + +def check_subprocess_cmd(cmd, process_num, timeout): + + for i in range(process_num): + p = subprocess.Popen(cmd.split()) + try: + p.wait(timeout=5) + except subprocess.TimeoutExpired: + p.kill() + + +def create_file_commands(local, remote, mode, num): + if mode == "send": + return [f"{GP.hdc_head} file send {local} {remote}_{i}" for i in range(num)] + elif mode == "recv": + return [f"{GP.hdc_head} file recv {remote}_{i} {local}_{i}" for i in range(num)] + else: + return [] + + +def create_dir_commands(local, remote, mode, num): + if mode == "send": + return [f"{GP.hdc_head} file send {local} {remote}" for _ in range(num)] + elif mode == "recv": + return [f"{GP.hdc_head} file recv {remote} {local}" for _ in range(num)] + else: + return [] + + +def execute_commands(commands): + processes = [subprocess.Popen(cmd.split(), stdout=subprocess.PIPE, stderr=subprocess.PIPE) for cmd in commands] + while processes: + for p in processes: + if not handle_process(p, processes, assert_out="FileTransfer finish"): + return False + return True + + +def handle_process(p, processes, assert_out="FileTransfer finish"): + if p.poll() is not None: + stdout, stderr = p.communicate(timeout=512) # timeout wait 512s + if stderr: + print(f"{stderr.decode()}") + if stdout: + print(f"{stdout.decode()}") + if assert_out is not None and stdout.decode().find(assert_out) == -1: + return False + processes.remove(p) + return True + + +def check_files(local, remote, mode, num): + res = 1 + for i in range(num): + if mode == "send": + if _check_file(local, f"{remote}_{i}"): + res *= 1 + else: + res *= 0 + elif mode == "recv": + if _check_file(f"{local}_{i}", f"{remote}_{i}"): + res *= 1 + else: + res *= 0 + return res == 1 + + +def check_dirs(local, remote, mode, num): + res = 1 + for _ in range(num): + if mode == "send": + end_of_file_name = os.path.basename(local) + if check_dir(local, f"{remote}/{end_of_file_name}", is_single_dir=True): + res *= 1 + else: + res *= 0 + elif mode == "recv": + end_of_file_name = os.path.basename(remote) + local = os.path.join(local, end_of_file_name) + if check_dir(f"{local}", f"{remote}", is_single_dir=True): + res *= 1 + else: + res *= 0 + return res == 1 + + +def make_multiprocess_file(local, remote, mode, num, task_type): + if num < 1: + return False + + if task_type == "file": + commands = create_file_commands(local, remote, mode, num) + elif task_type == "dir": + commands = create_dir_commands(local, remote, mode, num) + else: + return False + + print(commands[0]) + if not execute_commands(commands): + return False + + if task_type == "file": + return check_files(local, remote, mode, num) + elif task_type == "dir": + return check_dirs(local, remote, mode, num) + else: + return False + + +def hdc_get_key(cmd): + test_cmd = f"{GP.hdc_head} {cmd}" + result = subprocess.check_output(test_cmd.split()).decode() + return result + + +def check_hdc_version(cmd, version): + + def _convert_version_to_hex(_version): + parts = _version.split("Ver: ")[1].split('.') + hex_version = ''.join(parts) + return int(hex_version, 16) + + expected_version = _convert_version_to_hex(version) + cmd = f"{GP.hdc_head} -v" + print(f"\nexecuting command: {cmd}") + if version is not None: # check output valid + output = subprocess.check_output(cmd.split()).decode().replace("\r", "").replace("\n", "") + real_version = _convert_version_to_hex(output) + print(f"--> output: {output}") + print(f"--> your local [{version}] is" + f" {'' if expected_version <= real_version else 'too old to'} fit the version [{output}]" + ) + return expected_version <= real_version + + +def check_cmd_time(cmd, pattern, duration, times): + if times < 1: + print("times should be bigger than 0.") + return False + if pattern is None: + fetchable = True + else: + fetchable = False + start_time = time.time() * 1000 + print(f"{cmd} start {start_time}") + res = [] + for i in range(times): + start_in = time.time() * 1000 + if pattern is None: + subprocess.check_output(f"{GP.hdc_head} {cmd}".split()) + elif not check_shell(cmd, pattern, fetch=fetchable): + return False + start_out = time.time() * 1000 + res.append(start_out - start_in) + + # 计算最大值、最小值和中位数 + max_value = max(res) + min_value = min(res) + median_value = sorted(res)[len(res) // 2] + + print(f"{GP.hdc_head} {cmd}耗时最大值:{max_value}") + print(f"{GP.hdc_head} {cmd}耗时最小值:{min_value}") + print(f"{GP.hdc_head} {cmd}耗时中位数:{median_value}") + + end_time = time.time() * 1000 + + try: + timecost = int(end_time - start_time) / times + print(f"{GP.hdc_head} {cmd}耗时平均值 {timecost}") + except ZeroDivisionError: + print(f"除数为0") + + if duration is None: + duration = 150 * 1.2 + # 150ms is baseline timecost for hdc shell xxx cmd, 20% can be upper maybe system status + return timecost < duration + + +def check_rom(baseline): + + def _try_get_size(message): + try: + size = int(message.split('\t')[0]) + except ValueError: + size = -9999 * 1024 # error size + print(f"try get size value error, from {message}") + return size + + if baseline is None: + baseline = 2200 + # 2200KB is the baseline of hdcd and libhdc.dylib.so size all together + cmd_hdcd = f"{GP.hdc_head} shell du system/bin/hdcd" + result_hdcd = subprocess.check_output(cmd_hdcd.split()).decode() + hdcd_size = _try_get_size(result_hdcd) + cmd_libhdc = f"{GP.hdc_head} shell du system/lib/libhdc.dylib.so" + result_libhdc = subprocess.check_output(cmd_libhdc.split()).decode() + if "directory" in result_libhdc: + cmd_libhdc64 = f"{GP.hdc_head} shell du system/lib64/libhdc.dylib.so" + result_libhdc64 = subprocess.check_output(cmd_libhdc64.split()).decode() + if "directory" in result_libhdc64: + libhdc_size = 0 + else: + libhdc_size = _try_get_size(result_libhdc64) + else: + libhdc_size = _try_get_size(result_libhdc) + all_size = hdcd_size + libhdc_size + GP.hdcd_rom = all_size + if all_size < 0: + GP.hdcd_rom = "error" + return False + else: + GP.hdcd_rom = f"{all_size} KB" + if all_size > baseline: + print(f"rom size is {all_size}, overlimit baseline {baseline}") + return False + else: + print(f"rom size is {all_size}, underlimit baseline {baseline}") + return True + + +def run_command_with_timeout(command, timeout): + try: + result = subprocess.run(command, check=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, timeout=timeout) + return result.stdout.decode(), result.stderr.decode() + except subprocess.TimeoutExpired: + return None, "Command timed out" + except subprocess.CalledProcessError as e: + return None, e.stderr.decode() + + +def check_cmd_block(command, pattern, timeout=600): + # 启动子进程 + process = subprocess.Popen(command.split(), stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True) + + # 用于存储子进程的输出 + output = "" + + try: + # 读取子进程的输出 + output, _ = process.communicate(timeout=timeout) + except subprocess.TimeoutExpired: + process.terminate() + process.kill() + output, _ = process.communicate(timeout=timeout) + + print(f"--> output: {output}") + if pattern in output: + return True + else: + return False + + +def check_version(version): + def decorator(func): + @functools.wraps(func) + def wrapper(*args, **kwargs): + if not check_hdc_version("version", version) or not check_hdc_version("shell hdcd -v", version): + print("version does not match, ignore this case") + pytest.skip("Version does not match, test skipped.") + return func(*args, **kwargs) + return wrapper + return decorator + + +@pytest.fixture(scope='class', autouse=True) +def load_gp(request): + GP.load() + + +class ConfigFileNotFoundException(Exception): + """配置文件未找到异常""" + pass \ No newline at end of file -- Gitee