• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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        assert check_soft_local(get_local_path('small'), get_local_path('soft_small'),
214                                get_remote_path('it_small_soft'))
215        assert check_soft_remote('it_small_soft', get_remote_path('it_soft_small'),
216                                get_local_path('recv_soft_small'))
217
218
219class TestFileError:
220    @pytest.mark.L0
221    @pytest.mark.repeat(1)
222    def test_file_error(self):
223        assert check_hdc_cmd("target mount")
224        assert check_shell(
225            f"file recv",
226            "[Fail]There is no local and remote path"
227        )
228        assert check_shell(
229            f"file send",
230            "[Fail]There is no local and remote path"
231        )
232        assert check_hdc_cmd(f"shell rm -rf {get_remote_path('../../../large')}")
233        assert check_hdc_cmd(f"shell param set persist.hdc.control.file false")
234        assert check_shell(
235            f"file send {get_local_path('small')} {get_remote_path('it_small_false')}",
236            "debugging is not allowed"
237        )
238        assert check_hdc_cmd(f"shell param set persist.hdc.control.file true")
239        assert check_hdc_cmd(f"file send {get_local_path('small')} {get_remote_path('it_small_true')}")
240
241
242class TestFileBundleOptionNormal:
243    data_storage_el2_path = "data/storage/el2/base"
244
245    @classmethod
246    def setup_class(self):
247        check_shell(f"shell rm -rf mnt/debug/100/debug_hap/{GP.debug_app}/{self.data_storage_el2_path}/it*")
248        check_shell(f"shell mkdir -p mnt/debug/100/debug_hap/{GP.debug_app}/{self.data_storage_el2_path}")
249
250    @classmethod
251    def teardown_class(self):
252        pass
253
254    @pytest.mark.L0
255    @check_version("Ver: 3.1.0e")
256    @pytest.mark.parametrize("test_item", ['empty', 'medium', 'small', 'problem_dir'])
257    def test_file_option_bundle_normal(self, test_item):
258        if test_item == 'problem_dir' and os.path.exists(get_local_path(f'recv_bundle_{test_item}')):
259            rmdir(get_local_path(f'recv_bundle_{test_item}'))
260        assert check_hdc_cmd(f"file send -b {GP.debug_app} "
261                            f"{get_local_path(f'{test_item}')} {self.data_storage_el2_path}/it_{test_item}")
262        assert check_hdc_cmd(f"file recv -b {GP.debug_app} {self.data_storage_el2_path}/it_{test_item} "
263                            f"{get_local_path(f'recv_bundle_{test_item}')}")
264
265
266class TestFileBundleOptionError:
267    data_storage_el2_path = "data/storage/el2/base"
268    error_table = [
269        # 测试空文件夹发送和接收
270        ("Sending and receiving an empty folder",
271         f"file send -b {GP.debug_app} {get_local_path('empty_dir')} {get_remote_path('it_empty_dir')}",
272         "the source folder is empty"),
273
274        # 测试缺少本地和远程路径
275        ("Missing local and remote paths for send", f"file send -b {GP.debug_app}", "There is no local and remote path"),
276        ("Missing local and remote paths for recv", f"file recv -b {GP.debug_app}", "There is no local and remote path"),
277
278        # 测试错误优先级
279        ("Error priority for send", f"file send -b ./{GP.debug_app}", "There is no local and remote path"),
280        ("Error priority for recv", f"file recv -b ./{GP.debug_app}", "There is no local and remote path"),
281
282        # 测试缺少 bundle 参数
283        ("Missing bundle parameter for recv", f"file recv -b", "[E005003]"),
284        ("Missing bundle parameter for send", f"file send -b", "[E005003]"),
285
286        # 测试本地和远程路径错误
287        ("Incorrect local and remote paths for send",
288         f"file send -b ./{GP.debug_app} {get_local_path('small')} {get_remote_path('it_small')}", "[E005101]"),
289        ("Incorrect local and remote paths for recv",
290         f"file recv -b ./{GP.debug_app} {get_local_path('small')} {get_remote_path('it_small')}", "[E005101]"),
291
292        # 测试无效的 bundle 参数
293        ("invalid bundle parameter for send",
294         f"file send -b ./{GP.debug_app} {get_local_path('small')} {get_remote_path('it_small')}", "[E005101]"),
295        ("invalid bundle parameter with valid name for send",
296         f"file send -b com.AAAA {get_local_path('small')} {get_remote_path('it_small')}", "[E005101]"),
297        ("invalid bundle parameter with number for send",
298         f"file send -b 1 {get_local_path('small')} {get_remote_path('it_small')}", "[E005101]"),
299        ("Missing remote path for send",
300         f"file send -b {get_local_path('small')} {get_remote_path('it_small')}", "There is no remote path"),
301
302        # 测试远程路径错误
303        ("Incorrect remote path for recv",
304         f"file recv -b ./{GP.debug_app} {get_remote_path('it_small')} {get_local_path('small_recv')}", "[E005101]"),
305
306        # 测试路径逃逸
307        ("Path escaping for send",
308         f"file send -b {GP.debug_app} {get_local_path('small')} ../../../it_small", "[E005102]"),
309        ("Path escaping for recv",
310         f"file recv -b {GP.debug_app} ../../../it_small {get_local_path('small_recv')}", "[E005102]"),
311    ]
312    outside_error = "[E005102]"
313    outside_table = [
314        # bundle根目录 逃逸
315        ("Escape to parent directory", "..", True),
316        ("Escape two levels up", "../..", True),
317        ("Escape three levels up", "../../..", True),
318        ("Escape four levels up", "../../../..", True),
319        ("Escape to parent directory with current directory", "../.", True),
320        ("Escape to parent directory from current directory", "./..", True),
321        ("Escape to parent directory with slash", "../", True),
322        (f"Escape to extra app directory", f"../{GP.debug_app}_extra/{data_storage_el2_path}/", True),
323        (f"Escape to non-existent app directory", f"../{GP.debug_app}_notexsit/{data_storage_el2_path}/", True),
324        (f"Escape to non-existent app directory", f"../{GP.debug_app}_notexsit/", True),
325        (f"Escape far beyond root", "./../../../../../../../../../../aa", True),
326
327        # bundle根目录 未逃逸
328        ("Stays in the current directory", ".", False),
329        ("Stays in the current directory with slash", "./", False),
330        ("Stays in the current directory with current directory", "./.", False),
331        ("Stays in the current directory with ellipsis", "...", False),
332        (f"Stays at root and return bundle",
333            f"../../../../../../../../../../../mnt/debug/100/debug_hap/{GP.debug_app}/", False),
334    ]
335
336    @classmethod
337    def setup_class(self):
338        check_shell(f"shell rm -rf mnt/debug/100/debug_hap/{GP.debug_app}/{self.data_storage_el2_path}/it*")
339        check_shell(f"shell mkdir -p mnt/debug/100/debug_hap/{GP.debug_app}/{self.data_storage_el2_path}")
340        check_shell(f"shell rm -rf mnt/debug/100/debug_hap/{GP.debug_app}_extra/{self.data_storage_el2_path}/*")
341        check_shell(f"shell mkdir -p mnt/debug/100/debug_hap/{GP.debug_app}_extra/{self.data_storage_el2_path}/")
342
343    @classmethod
344    def teardown_class(self):
345        pass
346
347    @pytest.mark.L0
348    @check_version("Ver: 3.1.0e")
349    @pytest.mark.parametrize("test_name, command, expected", error_table,
350                             ids=[name for name, _, _ in error_table])
351    def test_file_option_bundle_error_(self, test_name, command, expected):
352        assert check_shell(command, expected)
353
354    @pytest.mark.parametrize("test_name, remote_path, is_outside", outside_table,
355                             ids=[name for name, _, _ in outside_table])
356    @pytest.mark.L0
357    @check_version("Ver: 3.1.0e")
358    def test_file_option_bundle_check_outside(self, test_name, remote_path, is_outside):
359        if is_outside:
360            assert check_shell(f"file send -b {GP.debug_app} {get_local_path('small')} {remote_path}",
361                               self.outside_error)
362        else:
363            assert not check_shell(f"file send -b {GP.debug_app} {get_local_path('small')} {remote_path}",
364                                   self.outside_error)