1#!/usr/bin/env python3 2# -*- coding: utf-8 -*- 3# Copyright (C) 2025 Huawei Device Co., Ltd. 4# Licensed under the Apache License, Version 2.0 (the "License"); 5# you may not use this file except in compliance with the License. 6# You may obtain a copy of the License at 7# 8# http://www.apache.org/licenses/LICENSE-2.0 9# 10# Unless required by applicable law or agreed to in writing, software 11# distributed under the License is distributed on an "AS IS" BASIS, 12# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13# See the License for the specific language governing permissions and 14# limitations under the License. 15import os 16import pytest 17 18from utils import GP, check_hdc_cmd, check_hdc_targets, check_soft_local, check_soft_remote, \ 19 check_shell, rmdir, check_version, get_local_path, get_remote_path, make_multiprocess_file, load_gp 20 21 22def clear_env(): 23 check_hdc_cmd("shell rm -rf data/local/tmp/it_*") 24 check_hdc_cmd("shell mkdir data/local/tmp/it_send_dir") 25 26 27def list_targets(): 28 assert check_hdc_targets() 29 30 31class TestFileCompress: 32 compress_file_table = [ 33 ("medium", "it_medium_z"), 34 ("word_100M.txt", "word_100M_compress.txt") 35 ] 36 37 @pytest.mark.L1 38 @pytest.mark.repeat(1) 39 @check_version("Ver: 3.1.0e") 40 @pytest.mark.parametrize("local_path, remote_path", compress_file_table) 41 def test_file_compress(self, local_path, remote_path): 42 clear_env() 43 assert check_hdc_cmd(f"file send -z {get_local_path(local_path)} {get_remote_path(remote_path)}") 44 assert check_hdc_cmd(f"file recv -z {get_remote_path(remote_path)} {get_local_path(f'{local_path}_recv')}") 45 46 47class TestFileBase: 48 base_file_table = [ 49 ("empty", "it_empty"), 50 ("small", "it_small"), 51 ("medium", "it_medium"), 52 ("large", "it_large"), 53 ("word_100M.txt", "word_100M") 54 ] 55 56 @pytest.mark.L0 57 @pytest.mark.repeat(2) 58 @pytest.mark.parametrize("local_path, remote_path", base_file_table) 59 def test_file_normal(self, local_path, remote_path): 60 clear_env() 61 assert check_hdc_cmd(f"file send {get_local_path(local_path)} {get_remote_path(remote_path)}") 62 assert check_hdc_cmd(f"file recv {get_remote_path(remote_path)} {get_local_path(f'{local_path}_recv')}") 63 64 65class TestDirBase: 66 @pytest.mark.L0 67 @pytest.mark.repeat(2) 68 def test_empty_dir(self): 69 clear_env() 70 assert check_shell(f"file send {get_local_path('empty_dir')} {get_remote_path('it_empty_dir')}", 71 "the source folder is empty") 72 assert check_hdc_cmd("shell mkdir data/local/tmp/it_empty_dir_recv") 73 assert check_shell(f"file recv {get_remote_path('it_empty_dir_recv')} {get_local_path('empty_dir_recv')}", 74 "the source folder is empty") 75 76 @pytest.mark.L0 77 @pytest.mark.repeat(2) 78 def test_long_path(self): 79 clear_env() 80 assert check_hdc_cmd(f"file send {get_local_path('deep_test_dir')} {get_remote_path('it_send_dir')}", 81 is_single_dir=False) 82 assert check_hdc_cmd(f"file recv {get_remote_path('it_send_dir/deep_test_dir')} " 83 f"{get_local_path('recv_test_dir')}", 84 is_single_dir=False) 85 86 @pytest.mark.L0 87 @pytest.mark.repeat(2) 88 def test_recv_dir(self): 89 if os.path.exists(get_local_path('it_problem_dir')): 90 rmdir(get_local_path('it_problem_dir')) 91 assert check_hdc_cmd(f"shell rm -rf {get_remote_path('it_problem_dir')}") 92 assert check_hdc_cmd(f"shell rm -rf {get_remote_path('problem_dir')}") 93 assert make_multiprocess_file(get_local_path('problem_dir'), get_remote_path(''), 'send', 1, "dir") 94 assert check_hdc_cmd(f"shell mv {get_remote_path('problem_dir')} {get_remote_path('it_problem_dir')}") 95 assert make_multiprocess_file(get_local_path(''), get_remote_path('it_problem_dir'), 'recv', 1, "dir") 96 97 98class TestDirMix: 99 muti_num = 5 # the count of multiprocess file 100 file_table = ['empty', 'medium', 'small'] 101 102 @classmethod 103 def setup_class(self): 104 pass 105 106 @classmethod 107 def teardown_class(self): 108 for test_item in self.file_table: 109 for i in range(0, self.muti_num - 1): 110 rmdir(get_local_path(f"{test_item}_recv_{i}")) 111 112 @pytest.mark.L1 113 @pytest.mark.repeat(2) 114 @pytest.mark.parametrize("test_item", file_table) 115 def test_mix_file(self, test_item): 116 assert make_multiprocess_file(get_local_path(f'{test_item}'), get_remote_path(f'it_{test_item}'), 117 'send', self.muti_num, "file") 118 assert make_multiprocess_file(get_local_path(f'{test_item}_recv'), get_remote_path(f'it_{test_item}'), 119 'recv', self.muti_num, "file") 120 121 122class TestFileNoExist: 123 remote_unexist_path = f"{get_remote_path('it_no_exist/deep_test_dir/')}" 124 125 @pytest.mark.L0 126 @pytest.mark.repeat(2) 127 @pytest.mark.parametrize("test_item", ['empty', 'medium', 'small', 'problem_dir']) 128 def test_no_exist_path(self, test_item): 129 check_hdc_cmd(f"shell rm -rf {get_remote_path('it_no_exist*')}") 130 local_unexist_path = get_local_path(f'{(os.path.join("recv_no_exist", "deep_test_dir", f"recv_{test_item}"))}') 131 if os.path.exists(get_local_path('recv_no_exist')): 132 rmdir(get_local_path('recv_no_exist')) 133 if test_item in ['empty', 'medium', 'small']: 134 assert check_shell(f"file send " 135 f"{get_local_path(f'{test_item}')} {self.remote_unexist_path}/it_{test_item}", 136 "no such file or directory") 137 assert check_shell(f"file recv {self.remote_unexist_path}/it_{test_item} " 138 f"{local_unexist_path}", 139 "no such file or directory") 140 else: 141 assert check_hdc_cmd(f"file send " 142 f"{get_local_path(f'{test_item}')} {self.remote_unexist_path}/it_{test_item}") 143 assert check_hdc_cmd(f"file recv {self.remote_unexist_path}/it_{test_item} " 144 f"{local_unexist_path}") 145 146 @pytest.mark.L0 147 @pytest.mark.repeat(2) 148 @pytest.mark.parametrize("test_item", ['empty', 'medium', 'small']) 149 def test_no_exist_path_with_seperate(self, test_item): 150 check_hdc_cmd(f"shell rm -rf {get_remote_path('it_no_exist*')}") 151 local_unexist_path = get_local_path(f'{(os.path.join("recv_no_exist", "deep_test_dir"))}') 152 if os.path.exists(get_local_path('recv_no_exist')): 153 rmdir(get_local_path('recv_no_exist')) 154 assert check_shell(f"file send " 155 f"{get_local_path(f'{test_item}')} {self.remote_unexist_path}/", 156 "no such file or directory") 157 assert check_shell(f"file recv {self.remote_unexist_path}/{test_item} " 158 f"{local_unexist_path}{os.sep}", 159 "no such file or directory") 160 161 162class TestFileNoExistBundelPath: 163 data_storage_el2_path = "data/storage/el2/base" 164 remote_unexist_path = f"{data_storage_el2_path}/it_no_exist/deep_test_dir/" 165 166 @classmethod 167 def setup_class(self): 168 check_shell(f"shell mkdir -p mnt/debug/100/debug_hap/{GP.debug_app}/{self.data_storage_el2_path}") 169 170 @pytest.mark.L0 171 @pytest.mark.repeat(3) 172 @check_version("Ver: 3.1.0e") 173 @pytest.mark.parametrize("test_item", ['empty', 'medium', 'small', 'problem_dir']) 174 def test_no_exist_bundle_path(self, test_item): 175 check_hdc_cmd(f"shell -b {GP.debug_app} rm -rf {self.data_storage_el2_path}/it_no_exist/") 176 local_unexist_path = get_local_path( 177 f'{(os.path.join("recv_no_exist", "deep_test_dir", f"recv_{test_item}"))}') 178 if os.path.exists(get_local_path('recv_no_exist')): 179 rmdir(get_local_path('recv_no_exist')) 180 181 assert check_hdc_cmd(f"shell -b {GP.debug_app} ls {self.data_storage_el2_path}/it_no_exist", 182 "No such file or directory") 183 assert not os.path.exists(get_local_path('recv_no_exist')) 184 if test_item in ['empty', 'medium', 'small']: 185 assert check_shell(f"file send -b {GP.debug_app} " 186 f"{get_local_path(f'{test_item}')} {self.remote_unexist_path}/it_{test_item}", 187 "no such file or directory") 188 assert check_shell(f"file recv -b {GP.debug_app} {self.remote_unexist_path}/it_{test_item} " 189 f"{local_unexist_path}", 190 "no such file or directory") 191 else: 192 assert check_hdc_cmd(f"file send -b {GP.debug_app} " 193 f"{get_local_path(f'{test_item}')} {self.remote_unexist_path}/it_{test_item}") 194 assert check_hdc_cmd(f"file recv -b {GP.debug_app} {self.remote_unexist_path}/it_{test_item} " 195 f"{local_unexist_path}") 196 197 198class TestFileExtend: 199 @pytest.mark.L0 200 @pytest.mark.repeat(1) 201 def test_node_file(self): 202 assert check_hdc_cmd(f"file recv {get_remote_path('../../../sys/power/state')} {get_local_path('state')}") 203 assert check_hdc_cmd(f"file recv {get_remote_path('../../../sys/firmware/fdt')} {get_local_path('fdt')}") 204 205 @pytest.mark.L0 206 @pytest.mark.repeat(1) 207 def test_running_file(self): 208 assert check_hdc_cmd(f"file recv system/bin/hdcd {get_local_path('running_recv')}") 209 210 @pytest.mark.L2 211 @pytest.mark.repeat(2) 212 def test_soft_link(self): 213 if not os.path.exists(get_local_path('soft_small')): 214 pytest.skip("创建软链接失败,请使用管理员权限执行[python prepare.py -s]重新配置资源。") 215 assert check_soft_local(get_local_path('small'), get_local_path('soft_small'), 216 get_remote_path('it_small_soft')) 217 assert check_soft_remote('it_small_soft', get_remote_path('it_soft_small'), 218 get_local_path('recv_soft_small')) 219 220 @pytest.mark.L2 221 @pytest.mark.repeat(2) 222 def test_soft_dir(self): 223 if not os.path.exists(get_local_path('soft_dir')): 224 pytest.skip("创建软链接失败,请使用管理员权限执行[python prepare.py -s]重新配置资源。") 225 assert check_hdc_cmd(f"file send {get_local_path('small')} {get_remote_path('recv_small')}") 226 assert check_hdc_cmd(f"file recv {get_remote_path('recv_small')} " 227 f"{os.path.join(get_local_path('soft_dir'), 'd2', 'it_recv_small')}") 228 rmdir(os.path.join(get_local_path('soft_dir'), 'd2', 'it_recv_small')) 229 230 231class TestFileError: 232 @pytest.mark.L0 233 @pytest.mark.repeat(1) 234 def test_file_error(self): 235 assert check_hdc_cmd("target mount") 236 assert check_shell( 237 f"file recv", 238 "[Fail]There is no local and remote path" 239 ) 240 assert check_shell( 241 f"file send", 242 "[Fail]There is no local and remote path" 243 ) 244 assert check_hdc_cmd(f"shell rm -rf {get_remote_path('../../../large')}") 245 assert check_hdc_cmd(f"shell param set persist.hdc.control.file false") 246 assert check_shell( 247 f"file send {get_local_path('small')} {get_remote_path('it_small_false')}", 248 "debugging is not allowed" 249 ) 250 assert check_hdc_cmd(f"shell param set persist.hdc.control.file true") 251 assert check_hdc_cmd(f"file send {get_local_path('small')} {get_remote_path('it_small_true')}") 252 253 254class TestFileBundleOptionNormal: 255 data_storage_el2_path = "data/storage/el2/base" 256 257 @classmethod 258 def setup_class(self): 259 check_shell(f"shell rm -rf mnt/debug/100/debug_hap/{GP.debug_app}/{self.data_storage_el2_path}/it*") 260 check_shell(f"shell mkdir -p mnt/debug/100/debug_hap/{GP.debug_app}/{self.data_storage_el2_path}") 261 262 @classmethod 263 def teardown_class(self): 264 pass 265 266 @pytest.mark.L0 267 @check_version("Ver: 3.1.0e") 268 @pytest.mark.parametrize("test_item", ['empty', 'medium', 'small', 'problem_dir']) 269 def test_file_option_bundle_normal(self, test_item): 270 if test_item == 'problem_dir' and os.path.exists(get_local_path(f'recv_bundle_{test_item}')): 271 rmdir(get_local_path(f'recv_bundle_{test_item}')) 272 assert check_hdc_cmd(f"file send -b {GP.debug_app} " 273 f"{get_local_path(f'{test_item}')} {self.data_storage_el2_path}/it_{test_item}") 274 assert check_hdc_cmd(f"file recv -b {GP.debug_app} {self.data_storage_el2_path}/it_{test_item} " 275 f"{get_local_path(f'recv_bundle_{test_item}')}") 276 277 278class TestFileBundleOptionError: 279 data_storage_el2_path = "data/storage/el2/base" 280 error_table = [ 281 # 测试空文件夹发送和接收 282 ("Sending and receiving an empty folder", 283 f"file send -b {GP.debug_app} {get_local_path('empty_dir')} {get_remote_path('it_empty_dir')}", 284 "the source folder is empty"), 285 286 # 测试缺少本地和远程路径 287 ("Missing local and remote paths for send", f"file send -b {GP.debug_app}", "There is no local and remote path"), 288 ("Missing local and remote paths for recv", f"file recv -b {GP.debug_app}", "There is no local and remote path"), 289 290 # 测试错误优先级 291 ("Error priority for send", f"file send -b ./{GP.debug_app}", "There is no local and remote path"), 292 ("Error priority for recv", f"file recv -b ./{GP.debug_app}", "There is no local and remote path"), 293 294 # 测试缺少 bundle 参数 295 ("Missing bundle parameter for recv", f"file recv -b", "[E005003]"), 296 ("Missing bundle parameter for send", f"file send -b", "[E005003]"), 297 298 # 测试本地和远程路径错误 299 ("Incorrect local and remote paths for send", 300 f"file send -b ./{GP.debug_app} {get_local_path('small')} {get_remote_path('it_small')}", "[E005101]"), 301 ("Incorrect local and remote paths for recv", 302 f"file recv -b ./{GP.debug_app} {get_local_path('small')} {get_remote_path('it_small')}", "[E005101]"), 303 304 # 测试无效的 bundle 参数 305 ("invalid bundle parameter for send", 306 f"file send -b ./{GP.debug_app} {get_local_path('small')} {get_remote_path('it_small')}", "[E005101]"), 307 ("invalid bundle parameter with valid name for send", 308 f"file send -b com.AAAA {get_local_path('small')} {get_remote_path('it_small')}", "[E005101]"), 309 ("invalid bundle parameter with number for send", 310 f"file send -b 1 {get_local_path('small')} {get_remote_path('it_small')}", "[E005101]"), 311 ("Missing remote path for send", 312 f"file send -b {get_local_path('small')} {get_remote_path('it_small')}", "There is no remote path"), 313 314 # 测试远程路径错误 315 ("Incorrect remote path for recv", 316 f"file recv -b ./{GP.debug_app} {get_remote_path('it_small')} {get_local_path('small_recv')}", "[E005101]"), 317 318 # 测试路径逃逸 319 ("Path escaping for send", 320 f"file send -b {GP.debug_app} {get_local_path('small')} ../../../it_small", "[E005102]"), 321 ("Path escaping for recv", 322 f"file recv -b {GP.debug_app} ../../../it_small {get_local_path('small_recv')}", "[E005102]"), 323 ] 324 outside_error = "[E005102]" 325 outside_table = [ 326 # bundle根目录 逃逸 327 ("Escape to parent directory", "..", True), 328 ("Escape two levels up", "../..", True), 329 ("Escape three levels up", "../../..", True), 330 ("Escape four levels up", "../../../..", True), 331 ("Escape to parent directory with current directory", "../.", True), 332 ("Escape to parent directory from current directory", "./..", True), 333 ("Escape to parent directory with slash", "../", True), 334 (f"Escape to extra app directory", f"../{GP.debug_app}_extra/{data_storage_el2_path}/", True), 335 (f"Escape to non-existent app directory", f"../{GP.debug_app}_notexsit/{data_storage_el2_path}/", True), 336 (f"Escape to non-existent app directory", f"../{GP.debug_app}_notexsit/", True), 337 (f"Escape far beyond root", "./../../../../../../../../../../aa", True), 338 339 # bundle根目录 未逃逸 340 ("Stays in the current directory", ".", False), 341 ("Stays in the current directory with slash", "./", False), 342 ("Stays in the current directory with current directory", "./.", False), 343 ("Stays in the current directory with ellipsis", "...", False), 344 (f"Stays at root and return bundle", 345 f"../../../../../../../../../../../mnt/debug/100/debug_hap/{GP.debug_app}/", False), 346 ] 347 348 @classmethod 349 def setup_class(self): 350 check_shell(f"shell rm -rf mnt/debug/100/debug_hap/{GP.debug_app}/{self.data_storage_el2_path}/it*") 351 check_shell(f"shell mkdir -p mnt/debug/100/debug_hap/{GP.debug_app}/{self.data_storage_el2_path}") 352 check_shell(f"shell rm -rf mnt/debug/100/debug_hap/{GP.debug_app}_extra/{self.data_storage_el2_path}/*") 353 check_shell(f"shell mkdir -p mnt/debug/100/debug_hap/{GP.debug_app}_extra/{self.data_storage_el2_path}/") 354 355 @classmethod 356 def teardown_class(self): 357 pass 358 359 @pytest.mark.L0 360 @check_version("Ver: 3.1.0e") 361 @pytest.mark.parametrize("test_name, command, expected", error_table, 362 ids=[name for name, _, _ in error_table]) 363 def test_file_option_bundle_error_(self, test_name, command, expected): 364 assert check_shell(command, expected) 365 366 @pytest.mark.parametrize("test_name, remote_path, is_outside", outside_table, 367 ids=[name for name, _, _ in outside_table]) 368 @pytest.mark.L0 369 @check_version("Ver: 3.1.0e") 370 def test_file_option_bundle_check_outside(self, test_name, remote_path, is_outside): 371 if is_outside: 372 assert check_shell(f"file send -b {GP.debug_app} {get_local_path('small')} {remote_path}", 373 self.outside_error) 374 else: 375 assert not check_shell(f"file send -b {GP.debug_app} {get_local_path('small')} {remote_path}", 376 self.outside_error)