Merge lp:~canonical-platform-qa/ubuntu-system-tests/mtp_refactoring_merge_and_bugfix into lp:ubuntu-system-tests
- mtp_refactoring_merge_and_bugfix
- Merge into trunk
Status: | Merged |
---|---|
Approved by: | Brendan Donegan |
Approved revision: | 155 |
Merged at revision: | 153 |
Proposed branch: | lp:~canonical-platform-qa/ubuntu-system-tests/mtp_refactoring_merge_and_bugfix |
Merge into: | lp:ubuntu-system-tests |
Diff against target: |
816 lines (+397/-244) 4 files modified
ubuntu_system_tests/helpers/file_system.py (+10/-3) ubuntu_system_tests/helpers/mtp.py (+302/-0) ubuntu_system_tests/helpers/ssh.py (+14/-5) ubuntu_system_tests/tests/test_mtp.py (+71/-236) |
To merge this branch: | bzr merge lp:~canonical-platform-qa/ubuntu-system-tests/mtp_refactoring_merge_and_bugfix |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Richard Huddie (community) | Approve | ||
Brendan Donegan (community) | Approve | ||
PS Jenkins bot | continuous-integration | Approve | |
Sergio Cazzolato | Pending | ||
Review via email: mp+265084@code.launchpad.net |
Commit message
.MTP helper created including different objects to manage mtp tests and allowing any other test to use mtp feature.
.Merge with scope test. New filesystem paths are being used in the mtp tests.
.Fix clean_dir method of the filesystem helper. The old implementation was making the media scanner fail after the media dir is cleaned.
Description of the change
PS Jenkins bot (ps-jenkins) wrote : | # |
- 155. By Sergio Cazzolato
-
Fix test cases test_copy_
large_number_ of_files
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:155
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Brendan Donegan (brendan-donegan) wrote : | # |
Code looks fine and everything seems to still work
Richard Huddie (rhuddie) wrote : | # |
Looks good, I ran a test and it worked fine.
Preview Diff
1 | === modified file 'ubuntu_system_tests/helpers/file_system.py' |
2 | --- ubuntu_system_tests/helpers/file_system.py 2015-07-15 11:06:17 +0000 |
3 | +++ ubuntu_system_tests/helpers/file_system.py 2015-07-17 19:25:19 +0000 |
4 | @@ -51,6 +51,8 @@ |
5 | DIR_TEST_DATA_TEXT = os.path.join(DIR_TEST_DATA, 'text') |
6 | DIR_TEST_DATA_VIDEO = os.path.join(DIR_TEST_DATA, 'video') |
7 | |
8 | +DIR_TEMP = '/tmp' |
9 | + |
10 | |
11 | def delete_file(file_name): |
12 | """Delete the file passed as parameter. In case the file does not |
13 | @@ -78,13 +80,18 @@ |
14 | |
15 | def remove_dir(dir_path): |
16 | """Remove the directory""" |
17 | - shutil.rmtree(dir_path, True) |
18 | + if os.path.isdir(dir_path): |
19 | + shutil.rmtree(dir_path, True) |
20 | |
21 | |
22 | def clean_dir(dir_path): |
23 | """Delete all the content of the directory""" |
24 | - remove_dir(dir_path) |
25 | - os.makedirs(dir_path) |
26 | + for obj in os.listdir(dir_path): |
27 | + obj_path = os.path.join(dir_path, obj) |
28 | + if os.path.isfile(obj_path): |
29 | + os.remove(obj_path) |
30 | + else: |
31 | + remove_dir(obj_path) |
32 | |
33 | |
34 | def calculate_file_sha1(file_path): |
35 | |
36 | === added file 'ubuntu_system_tests/helpers/mtp.py' |
37 | --- ubuntu_system_tests/helpers/mtp.py 1970-01-01 00:00:00 +0000 |
38 | +++ ubuntu_system_tests/helpers/mtp.py 2015-07-17 19:25:19 +0000 |
39 | @@ -0,0 +1,302 @@ |
40 | + |
41 | +# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*- |
42 | + |
43 | +# Ubuntu System Tests |
44 | +# Copyright (C) 2015 Canonical |
45 | +# |
46 | +# This program is free software: you can redistribute it and/or modify |
47 | +# it under the terms of the GNU General Public License as published by |
48 | +# the Free Software Foundation, either version 3 of the License, or |
49 | +# (at your option) any later version. |
50 | +# |
51 | +# This program is distributed in the hope that it will be useful, |
52 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
53 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
54 | +# GNU General Public License for more details. |
55 | +# |
56 | +# You should have received a copy of the GNU General Public License |
57 | +# along with this program. If not, see <http://www.gnu.org/licenses/>. |
58 | + |
59 | +import logging |
60 | +import os |
61 | +import shutil |
62 | + |
63 | +from ubuntu_system_tests.helpers import file_system as fs |
64 | + |
65 | +logger = logging.getLogger(__name__) |
66 | + |
67 | +DEFAULT_XDG_RUNTIME_DIR = '/run/user/1000' |
68 | + |
69 | + |
70 | +class MTPObjBase: |
71 | + """ Base class used to represent objects that are copied through mtp""" |
72 | + |
73 | + def __init__(self, remote_helper): |
74 | + self.remote_helper = remote_helper |
75 | + self.local_src_path = "" |
76 | + self.local_dst_path = "" |
77 | + self.remote_src_path = "" |
78 | + self.remote_dst_path = "" |
79 | + |
80 | + def validate_remote_copy(self): |
81 | + """ Validate the src and dst paths are defined """ |
82 | + if not self.remote_src_path or not self.remote_dst_path: |
83 | + raise RuntimeError("Remote copy cannot be done, remote_src_path " |
84 | + "and remote_mtp_path have to be defined") |
85 | + |
86 | + def validate_send_to_host(self): |
87 | + """ Validate the src and dst paths are defined """ |
88 | + if not self.local_src_path or not self.remote_src_path: |
89 | + raise RuntimeError("Send to host cannot be done, local_src_path " |
90 | + "and remote_src_path have to be defined") |
91 | + |
92 | + |
93 | +class MTPFile(MTPObjBase): |
94 | + """ This class represents a file which is copied through mtp""" |
95 | + |
96 | + def __init__(self, remote_helper): |
97 | + super(MTPFile, self).__init__(remote_helper) |
98 | + self.sha1 = "" |
99 | + |
100 | + @property |
101 | + def name(self): |
102 | + """ Retrieve the name based of the paths defined """ |
103 | + return os.path.basename(self.local_src_path) or \ |
104 | + os.path.basename(self.remote_src_path) or \ |
105 | + os.path.basename(self.remote_dst_path) or \ |
106 | + os.path.basename(self.local_dst_path) |
107 | + |
108 | + def clean(self): |
109 | + """ Clean the file in the different places where the file has been |
110 | + copied. This method is used mainly for the clean up of the file """ |
111 | + fs.delete_file(self.local_src_path) |
112 | + if self.remote_src_path: |
113 | + self.remote_helper.remove_file(self.remote_src_path) |
114 | + if self.remote_dst_path: |
115 | + self.remote_helper.remove_file(self.remote_dst_path) |
116 | + fs.delete_file(self.local_dst_path) |
117 | + |
118 | + def remote_copy(self, remote_dst_path=None): |
119 | + """ Copy the file in the remote host from src to dst |
120 | + :param remote_dst_path: the remote destination in case it has not been |
121 | + defined previously |
122 | + """ |
123 | + if remote_dst_path: |
124 | + self.remote_dst_path = remote_dst_path |
125 | + self.validate_remote_copy() |
126 | + logger.info("Copying remote file from {src_path} to {mtp_path}". |
127 | + format(src_path=self.remote_src_path, |
128 | + mtp_path=self.remote_dst_path)) |
129 | + self.remote_helper.copy_file(self.remote_src_path, |
130 | + self.remote_dst_path) |
131 | + |
132 | + def get_remote_dst_sha1(self): |
133 | + """ Get the sha1 digest calculated in the remote host for the file |
134 | + located in the remote_dst_path |
135 | + """ |
136 | + if not self.remote_dst_path: |
137 | + raise RuntimeError("Attribute remote_dst_path has to de defined") |
138 | + return self.remote_helper.get_sha1(self.remote_dst_path) |
139 | + |
140 | + def send_to_host(self, path=None): |
141 | + """ Send the file from the device to the ubuntu host. The |
142 | + remote_src_path will be updated in case the path is defined |
143 | + :param path: The path in the remote host where the file is copied |
144 | + """ |
145 | + if path: |
146 | + self.remote_src_path = os.path.join(path, self.name) |
147 | + self.validate_send_to_host() |
148 | + logger.info("Sending file to remote host from {local_path} to " |
149 | + "{remote_path}".format(local_path=self.local_src_path, |
150 | + remote_path=self.remote_src_path)) |
151 | + self.remote_helper.put(self.local_src_path, self.remote_src_path) |
152 | + |
153 | + def compare(self, file_path): |
154 | + """ Compare the local file to the file located in the path |
155 | + :return:True if the files are equal, false otherwise |
156 | + """ |
157 | + return fs.compare_files(self.local_src_path, file_path) |
158 | + |
159 | + |
160 | +class MTPDir(MTPObjBase): |
161 | + """ This class represents a directory which is copied through mtp""" |
162 | + |
163 | + def __init__(self, remote_helper): |
164 | + super(MTPDir, self).__init__(remote_helper) |
165 | + |
166 | + @property |
167 | + def name(self): |
168 | + """ Retrieve the name based of the paths defined """ |
169 | + return os.path.basename(self.local_src_path) or \ |
170 | + os.path.basename(self.remote_src_path) or \ |
171 | + os.path.basename(self.remote_dst_path) or \ |
172 | + os.path.basename(self.local_dst_path) |
173 | + |
174 | + def clean(self): |
175 | + """ Clean the dir in the different places where the dir has been |
176 | + copied. This method is used mainly for the clean up of the dir """ |
177 | + fs.remove_dir(self.local_src_path) |
178 | + if self.remote_src_path: |
179 | + self.remote_helper.remove_dir(self.remote_src_path) |
180 | + if self.remote_dst_path: |
181 | + self.remote_helper.remove_dir(self.remote_dst_path) |
182 | + fs.remove_dir(self.local_dst_path) |
183 | + |
184 | + def remote_copy(self, remote_dst_path=None): |
185 | + """ Copy the dir in the remote host from src to dst |
186 | + :param remote_dst_path: the remote destination in case it has not been |
187 | + defined previously |
188 | + """ |
189 | + if remote_dst_path: |
190 | + self.remote_dst_path = remote_dst_path |
191 | + self.validate_remote_copy() |
192 | + logger.info("Copying remote directory from {src_path} to {mtp_path}". |
193 | + format(src_path=self.remote_src_path, |
194 | + mtp_path=self.remote_dst_path)) |
195 | + self.remote_helper.copy_dir(self.remote_src_path, |
196 | + self.remote_dst_path) |
197 | + |
198 | + |
199 | +class MTPObjFactory: |
200 | + """ A factory class used to create the mtp entities in the local and |
201 | + remote host """ |
202 | + |
203 | + def __init__(self, remote_helper, clean_up): |
204 | + """ |
205 | + :param remote_helper: The helper to interact with the remote host |
206 | + :param clean_up: The method used to clean up the objects created |
207 | + """ |
208 | + self.remote_helper = remote_helper |
209 | + self.clean_up = clean_up |
210 | + |
211 | + def new_file(self): |
212 | + """ Create an MTPFile object and add a clean up for it """ |
213 | + file = MTPFile(self.remote_helper) |
214 | + self.clean_up(file.clean) |
215 | + return file |
216 | + |
217 | + def create_random_file(self, dir, ext='', sha1=True): |
218 | + """ Create a MTPFile object with random name |
219 | + :param dir: The dir where the file is created |
220 | + :param ext: The extension of the file to be created |
221 | + :param sha1: if True, the sha1 is calculated and stores in the file |
222 | + :return: The created file with the local src path already set |
223 | + """ |
224 | + file = self.new_file() |
225 | + file.local_src_path = fs.create_random_file(dir, ext) |
226 | + if sha1: |
227 | + file.sha1 = fs.calculate_file_sha1(file.local_src_path) |
228 | + return file |
229 | + |
230 | + def create_file(self, src_file, temp=True): |
231 | + """ Create a MTPFile object based on a real file |
232 | + :param src_file: The real file used to create the MTPFile obj |
233 | + :param temp: if True, the file is copied to a temp dir. The temp is |
234 | + used to avoid the original file is deleted in the clean-up |
235 | + :return: The created file object with the local src path already set |
236 | + """ |
237 | + file = self.new_file() |
238 | + file.local_src_path = src_file |
239 | + if temp: |
240 | + file.local_src_path = os.path.join(fs.DIR_TEMP, file.name) |
241 | + shutil.copy(src_file, file.local_src_path) |
242 | + return file |
243 | + |
244 | + def create_remote_file(self, path=None, name=None, ext='', sha1=True, |
245 | + kb=0, mb=0, gb=0): |
246 | + """ Create a file in the remote host |
247 | + :param path: The path where the file is created, if None, the file will |
248 | + be created in a temp dir |
249 | + :param name: The name of the file to be created, if None, will be used |
250 | + a random name |
251 | + :param ext: the extension of the file |
252 | + :param sha1: if True, the sha1 is calculated and stores in the file |
253 | + :param kb: The kilobytes of the file to be created |
254 | + :param mb: The megabytes of the file to be created |
255 | + :param gb: The gigabytes of the file to be created |
256 | + :return: The created file with random content and size equals to |
257 | + kb kilobytes + mb megabytes + gb gigabytes |
258 | + """ |
259 | + file = self.new_file() |
260 | + file_path = path or fs.DIR_TEMP |
261 | + file_name = name or fs.get_random_string() |
262 | + file.remote_src_path = os.path.join(file_path, file_name + ext) |
263 | + self.remote_helper.create_random_file(file.remote_src_path, kb=kb, |
264 | + mb=mb, gb=gb) |
265 | + if sha1: |
266 | + file.sha1 = self.remote_helper.get_sha1(file.remote_src_path) |
267 | + return file |
268 | + |
269 | + def new_dir(self): |
270 | + """ Create an MTPDir object and add a clean up for it """ |
271 | + dir = MTPDir(self.remote_helper) |
272 | + self.clean_up(dir.clean) |
273 | + return dir |
274 | + |
275 | + def create_remote_dir(self, path=None, name=None): |
276 | + """ |
277 | + Create a dir in the remote host |
278 | + :param path: the name path where the new dir has to be created |
279 | + :param name: the name of the dir, in case the name is not defined, |
280 | + a random name is used |
281 | + """ |
282 | + dir = self.new_dir() |
283 | + dir_path = path or fs.DIR_TEMP |
284 | + dir_name = name or fs.get_random_string() |
285 | + dir.remote_src_path = os.path.join(dir_path, dir_name) |
286 | + self.remote_helper.create_dir(dir.remote_src_path) |
287 | + return dir |
288 | + |
289 | + |
290 | +class MTPHelper: |
291 | + |
292 | + def __init__(self, remote_helper): |
293 | + self.remote_helper = remote_helper |
294 | + self.mtp_dir = self._calculate_mtp_dir() |
295 | + |
296 | + def get_mtp_path(self, *paths): |
297 | + """ Retrieve the mtp path following the desired paths |
298 | + :param paths: A list of subdir to the destination path |
299 | + :return: The mtp path already escaped to the destination path |
300 | + """ |
301 | + return '"' + os.path.join(self.mtp_dir, *paths) + '"' |
302 | + |
303 | + def _calculate_mtp_dir(self): |
304 | + """ Get the path in the ubuntu host machine which maps to the mtp dir. |
305 | + Use a random file to identify the device internal storage destination. |
306 | + """ |
307 | + file = fs.create_random_file(fs.DIR_HOME_DOCUMENTS, ext='.tmp') |
308 | + docs_mtp_dir = self._get_mtp_dir(fs.DIR_DOCUMENTS, |
309 | + os.path.basename(file)) |
310 | + os.remove(file) |
311 | + return os.path.dirname(docs_mtp_dir) |
312 | + |
313 | + def _get_mtp_dir(self, dir_to_map, filename): |
314 | + """ Determine the full_path in the ubuntu host machine which maps the |
315 | + file and directory in the device |
316 | + :param dir_to_map: The directory to map |
317 | + :param filename: The name of the file to be mapped |
318 | + :return: the full path that maps the dir_to_map and filename in the |
319 | + device |
320 | + """ |
321 | + cmd_line = "python3 -c \"import glob; import os; " \ |
322 | + "print(glob.glob(os.getenv('XDG_RUNTIME_DIR', " \ |
323 | + "'{default}') + '/gvfs/*/*/{dir}/{filename}')[0])\"".\ |
324 | + format(default=DEFAULT_XDG_RUNTIME_DIR, |
325 | + dir=dir_to_map, |
326 | + filename=filename) |
327 | + |
328 | + file_path = self.remote_helper.run(cmd_line).strip() |
329 | + if file_path: |
330 | + return os.path.dirname(file_path) |
331 | + return None |
332 | + |
333 | + def replicate_file(self, src_file, dst_dir, dst_files): |
334 | + """ Copy the src file to the dst directory with the different names |
335 | + stored in the dst_files variable |
336 | + :param src_file: the source file to replicate |
337 | + :param dst_dir: the destination directory to copy the files |
338 | + :param dst_files: the target names to use |
339 | + """ |
340 | + for file in dst_files: |
341 | + src_file.remote_copy(os.path.join(dst_dir.remote_src_path, file)) |
342 | |
343 | === modified file 'ubuntu_system_tests/helpers/ssh.py' |
344 | --- ubuntu_system_tests/helpers/ssh.py 2015-07-10 19:41:55 +0000 |
345 | +++ ubuntu_system_tests/helpers/ssh.py 2015-07-17 19:25:19 +0000 |
346 | @@ -21,6 +21,8 @@ |
347 | import os |
348 | import paramiko |
349 | |
350 | +from ubuntu_system_tests import config |
351 | + |
352 | logger = logging.getLogger(__name__) |
353 | |
354 | |
355 | @@ -45,19 +47,26 @@ |
356 | |
357 | return "".join(stdout.readlines()) |
358 | |
359 | - def copy(self, localpath, remotepath): |
360 | - """Copy a file through sftp from the localpath to the remotepath""" |
361 | - if not os.path.isfile(localpath): |
362 | + def put(self, local_path, remote_path): |
363 | + """Copy a file through sftp from the local_path to the remote_path""" |
364 | + if not os.path.isfile(local_path): |
365 | raise RuntimeError("File to copy does not exist") |
366 | |
367 | sftp = self.client.open_sftp() |
368 | - sftp.put(localpath, remotepath) |
369 | + sftp.put(local_path, remote_path) |
370 | sftp.close() |
371 | |
372 | |
373 | class LinuxRemoteHelper(SSH): |
374 | """This class executes remote linux commands through the ssh connection""" |
375 | |
376 | + def __init__(self): |
377 | + config_stack = config.get_device_config_stack() |
378 | + host = config_stack.get('ssh_ip') |
379 | + user = config_stack.get('ssh_user') |
380 | + password = config_stack.get('ssh_password') |
381 | + super(LinuxRemoteHelper, self).__init__(host, user, password) |
382 | + |
383 | def remove_dir(self, dir_name): |
384 | self.run('rm -rf {}'.format(dir_name)) |
385 | |
386 | @@ -85,7 +94,7 @@ |
387 | :param mb: The megabytes of the file |
388 | :param gb: The gigabytes fo the file |
389 | :return: The file path to the created file with random content and size |
390 | - equals to kb KiloBytes + mb MegaBytes + gb GigaBytes |
391 | + equals to kb kilobytes + mb megabytes + gb gigabytes |
392 | """ |
393 | count = kb + mb * 1024 + gb * 1024 * 1024 |
394 | self.run('dd if=/dev/urandom of={file} bs=1024 count={count}'. |
395 | |
396 | === modified file 'ubuntu_system_tests/tests/test_mtp.py' |
397 | --- ubuntu_system_tests/tests/test_mtp.py 2015-07-15 11:06:17 +0000 |
398 | +++ ubuntu_system_tests/tests/test_mtp.py 2015-07-17 19:25:19 +0000 |
399 | @@ -22,26 +22,14 @@ |
400 | import logging |
401 | import os |
402 | |
403 | -from ubuntu_system_tests import config |
404 | from ubuntu_system_tests.helpers import file_system as fs |
405 | +from ubuntu_system_tests.helpers.mtp import MTPObjFactory, MTPHelper |
406 | from ubuntu_system_tests.helpers import ssh |
407 | from ubuntu_system_tests.helpers.scopes import music |
408 | from ubuntu_system_tests.helpers.unity8.dash import get_dash |
409 | |
410 | from ubuntu_system_tests.tests import base |
411 | |
412 | -TEMP_DIR = '/tmp' |
413 | -DEFAULT_XDG_RUNTIME_DIR = '/run/user/1000' |
414 | - |
415 | -MUSIC = "Music" |
416 | -MUSIC_DIR = os.path.join(os.path.expanduser("~"), MUSIC) |
417 | -DOCS = "Documents" |
418 | -DOCS_DIR = os.path.join(os.path.expanduser("~"), DOCS) |
419 | -PICTURES = "Pictures" |
420 | -PICTURES_DIR = os.path.join(os.path.expanduser("~"), PICTURES) |
421 | -VIDEOS = "Videos" |
422 | -VIDEOS_DIR = os.path.join(os.path.expanduser("~"), VIDEOS) |
423 | - |
424 | FileMusicDesc = namedtuple('FileMusicDesc', ['file', 'album']) |
425 | logger = logging.getLogger(__name__) |
426 | songs_album_mp3 = ['song_1.mp3', 'song_2.mp3', 'song_3.mp3'] |
427 | @@ -57,108 +45,17 @@ |
428 | } |
429 | |
430 | |
431 | -class MTPFile: |
432 | - """ This class is a data model which represents a file to be copied |
433 | - through mtp |
434 | - """ |
435 | - def __init__(self, remote_helper): |
436 | - self.remote_helper = remote_helper |
437 | - self.local_path = "" |
438 | - self.remote_src_path = "" |
439 | - self.remote_dst_path = "" |
440 | - self.sha1 = "" |
441 | - |
442 | - @property |
443 | - def name(self): |
444 | - return os.path.basename(self.local_path) or "" |
445 | - |
446 | - def clean_file(self): |
447 | - if self.local_path: |
448 | - fs.delete_file(self.local_path) |
449 | - if self.remote_src_path: |
450 | - self.remote_helper.remove_file(self.remote_src_path) |
451 | - if self.remote_dst_path: |
452 | - self.remote_helper.remove_file(self.remote_dst_path) |
453 | - |
454 | - def remote_copy(self): |
455 | - if not self.remote_src_path or not self.remote_dst_path: |
456 | - raise RuntimeError("Remote copy cannot be done, it is required to " |
457 | - "define src and dst paths,") |
458 | - logger.info("Copying remote file from {src_path} to {dst_path}". |
459 | - format(src_path=self.remote_src_path, |
460 | - dst_path=self.remote_dst_path)) |
461 | - self.remote_helper.copy_file(self.remote_src_path, |
462 | - self.remote_dst_path) |
463 | - |
464 | - def get_remote_dst_sha1(self): |
465 | - if not self.remote_dst_path: |
466 | - raise RuntimeError("Attribute remote_dst_path has to de defined") |
467 | - return self.remote_helper.get_sha1(self.remote_dst_path) |
468 | - |
469 | - |
470 | class MTPTest(base.BaseUbuntuSystemTestCase): |
471 | """This Class tests the mtp protocol""" |
472 | |
473 | def setUp(self): |
474 | super().setUp() |
475 | |
476 | - self.config_stack = config.get_device_config_stack() |
477 | self.unity_proxy = self.restart_unity() |
478 | - self.remote_helper = ssh.LinuxRemoteHelper( |
479 | - self.config_stack.get('ssh_ip'), |
480 | - self.config_stack.get('ssh_user'), |
481 | - self.config_stack.get('ssh_password')) |
482 | + self.remote_helper = ssh.LinuxRemoteHelper() |
483 | self.addCleanup(self.remote_helper.close) |
484 | - self.mtp_dir = self.calculate_device_mtp_dir() |
485 | - |
486 | - def create_random_file(self, dir, ext='', sha1=True): |
487 | - file = MTPFile(self.remote_helper) |
488 | - file.local_path = fs.create_random_file(dir, ext) |
489 | - if sha1: |
490 | - file.sha1 = fs.calculate_file_sha1(file.local_path) |
491 | - self.addCleanup(file.clean_file) |
492 | - return file |
493 | - |
494 | - def get_first_elem_in_dir_command(self, path): |
495 | - """Command to retrieve the first element in a dir""" |
496 | - return 'ls {} | sort -n | head -1'.format(path) |
497 | - |
498 | - def get_device_mtp_dir(self, dir_to_map, filename): |
499 | - """ Determine the full_path in the ubuntu host machine which maps the |
500 | - file and directory in the device |
501 | - :param dir_to_map: The directory to map |
502 | - :param filename: The name of the file to be mapped |
503 | - :return: the full path that maps the dir_to_map and filename in the |
504 | - device |
505 | - """ |
506 | - cmd_line = "python3 -c \"import glob; import os; " \ |
507 | - "print(glob.glob(os.getenv('XDG_RUNTIME_DIR', " \ |
508 | - "'{default}') + '/gvfs/*/*/{dir}/{filename}')[0])\"".\ |
509 | - format(default=DEFAULT_XDG_RUNTIME_DIR, |
510 | - dir=dir_to_map, |
511 | - filename=filename) |
512 | - |
513 | - file_path = self.remote_helper.run(cmd_line).strip() |
514 | - if file_path: |
515 | - return os.path.dirname(file_path) |
516 | - return None |
517 | - |
518 | - def calculate_device_mtp_dir(self): |
519 | - """ Get the path in the ubuntu host machine which maps to the mtp dir. |
520 | - Use a random file to identify the device internal storage destination. |
521 | - """ |
522 | - file = fs.create_random_file(DOCS_DIR, ext='.tmp') |
523 | - self.addCleanup(os.remove, file) |
524 | - docs_mtp_dir = self.get_device_mtp_dir(DOCS, os.path.basename(file)) |
525 | - return os.path.dirname(docs_mtp_dir) |
526 | - |
527 | - def get_device_mtp_path(self, *paths): |
528 | - """ Retrieve the mtp path following the desired paths |
529 | - :param paths: A list of subdir to the destination path |
530 | - :return: The mtp path already escaped to the destination path |
531 | - """ |
532 | - dir = os.path.join(self.mtp_dir, *paths) |
533 | - return '"' + dir + '"' |
534 | + self.factory = MTPObjFactory(self.remote_helper, self.addCleanup) |
535 | + self.mtp_helper = MTPHelper(self.remote_helper) |
536 | |
537 | def verify_music_album_is_shown(self, album): |
538 | """ Determines if there is an album with the desired name in the music |
539 | @@ -169,33 +66,6 @@ |
540 | music_scope = music.MusicScope(get_dash().open_music_scope()) |
541 | self.assertTrue(music_scope.is_album(album)) |
542 | |
543 | - def create_remote_dir(self, parent_dir): |
544 | - """ |
545 | - Create a dir with random name in the remote host |
546 | - :param parent_dir: the name of the parent dir where the new dir has to |
547 | - be created |
548 | - :return: the dir name and its full path |
549 | - """ |
550 | - dir_name = fs.get_random_string() |
551 | - dir_path = os.path.join(parent_dir, dir_name) |
552 | - self.remote_helper.create_dir(dir_path) |
553 | - |
554 | - return dir_name, dir_path |
555 | - |
556 | - def copy_file_to_remote_host(self, file_path, remote_dir): |
557 | - """ Copy a local file to a remote host |
558 | - :param file_path: the local dire where the file is located |
559 | - :param remote_dir: the remote dir where the file is going to be copied |
560 | - :return: the full path of the file in the remote host |
561 | - """ |
562 | - dst_file = os.path.join(remote_dir, os.path.basename(file_path)) |
563 | - logger.info("Copying local file {file_path} to remote host on " |
564 | - "{dst_file}".format(file_path=file_path, |
565 | - dst_file=dst_file)) |
566 | - self.remote_helper.copy(file_path, dst_file) |
567 | - self.addCleanup(self.remote_helper.remove_file, dst_file) |
568 | - return dst_file |
569 | - |
570 | def verify_same_files(self, src_files, dst_files): |
571 | """ Verify both file lists contains the same files |
572 | :param src_files: list of src file names |
573 | @@ -210,67 +80,33 @@ |
574 | :param dst_files: list of files copied to the copied in the device |
575 | """ |
576 | for file in dst_files: |
577 | - self.assertTrue(fs.compare_files(src_file, |
578 | - os.path.join(dst_dir, file))) |
579 | - |
580 | - def replicate_file(self, src_file, dst_dir, dst_files): |
581 | - """ Copy the src file to the dst directory with the different names |
582 | - stored in the dst_files variable |
583 | - :param src_file: the source file to replicate |
584 | - :param dst_dir: the destination directory to copy the files |
585 | - :param dst_files: the target names to use |
586 | - """ |
587 | - for file in dst_files: |
588 | - self.remote_helper.copy_file(src_file, |
589 | - os.path.join(dst_dir, file)) |
590 | - |
591 | - def verify_file_copied(self, base_dir, file_name): |
592 | - """ Verify the file was copied to the base directory |
593 | - :param base_dir: the directory where the file has to be copied |
594 | - :param file_name: the name of the copied file |
595 | - :return: the destination path where the file was copied |
596 | - """ |
597 | - copied_file = os.path.join(base_dir, file_name) |
598 | - self.assertTrue(os.path.isfile(copied_file)) |
599 | - self.addCleanup(os.remove, copied_file) |
600 | - return copied_file |
601 | - |
602 | - def verify_dir_copied(self, base_dir, dir_name): |
603 | - """ Verify the dir was copied to the base directory |
604 | - :param base_dir: the directory where the dir name has to be copied |
605 | - :param dir_name: the name of the copied dir |
606 | - :return: the destination path where the dir was copied |
607 | - """ |
608 | - copied_dir = os.path.join(base_dir, dir_name) |
609 | - self.assertTrue(os.path.isdir(copied_dir)) |
610 | - self.addCleanup(fs.remove_dir, copied_dir) |
611 | - return copied_dir |
612 | - |
613 | - def prepare_music_albums(self, src_mp3_file, src_ogg_file): |
614 | + self.assertTrue(src_file.compare(os.path.join(dst_dir, file))) |
615 | + |
616 | + def prepare_music_albums(self, mp3_file, ogg_file): |
617 | """ Prepare the albums in the remote host with the song to be copied |
618 | It creates one dir with two albums inside, each album has 3 songs with |
619 | mp3 and ogg formats respectively |
620 | - :return: the |
621 | """ |
622 | |
623 | # Create music albums structure in the host machine |
624 | - (albums_name, albums_dir) = self.create_remote_dir(TEMP_DIR) |
625 | - (album_mp3_name, album_mp3_dir) = self.create_remote_dir(albums_dir) |
626 | - (album_ogg_name, album_ogg_dir) = self.create_remote_dir(albums_dir) |
627 | - self.addCleanup(self.remote_helper.remove_dir, albums_dir) |
628 | + albums_dir = self.factory.create_remote_dir() |
629 | + album_mp3_dir = self.factory.create_remote_dir( |
630 | + path=albums_dir.remote_src_path) |
631 | + album_ogg_dir = self.factory.create_remote_dir( |
632 | + path=albums_dir.remote_src_path) |
633 | |
634 | # Copy the music files to the ubuntu host machine |
635 | - dst_tmp_mp3_file = \ |
636 | - self.copy_file_to_remote_host(src_mp3_file, TEMP_DIR) |
637 | - dst_tmp_ogg_file = \ |
638 | - self.copy_file_to_remote_host(src_ogg_file, TEMP_DIR) |
639 | + mp3_file.send_to_host(fs.DIR_TEMP) |
640 | + ogg_file.send_to_host(fs.DIR_TEMP) |
641 | |
642 | # Copy the music files in the ubuntu host machine to the albums |
643 | # several times with different names and formats |
644 | - self.replicate_file(dst_tmp_mp3_file, album_mp3_dir, songs_album_mp3) |
645 | - self.replicate_file(dst_tmp_ogg_file, album_ogg_dir, songs_album_ogg) |
646 | + self.mtp_helper.replicate_file(mp3_file, album_mp3_dir, |
647 | + songs_album_mp3) |
648 | + self.mtp_helper.replicate_file(ogg_file, album_ogg_dir, |
649 | + songs_album_ogg) |
650 | |
651 | - return albums_name, albums_dir, album_mp3_name, album_ogg_name |
652 | + return albums_dir, album_mp3_dir, album_ogg_dir |
653 | |
654 | def verify_copied_files(self, seed_file, original_files, copied_dir): |
655 | """ Verify all the files have been copied correctly to the dst |
656 | @@ -307,27 +143,33 @@ |
657 | |
658 | # Prepare the albums structure in the remote machine previous to be |
659 | # copied to the device |
660 | - src_mp3_file = os.path.join(fs.DIR_TEST_DATA_AUDIO, |
661 | - test_data.get('mp3_file').file) |
662 | - src_ogg_file = os.path.join(fs.DIR_TEST_DATA_AUDIO, |
663 | - test_data.get('ogg_file').file) |
664 | - albums_name, albums_dir, album_mp3_name, album_ogg_name = \ |
665 | - self.prepare_music_albums(src_mp3_file, src_ogg_file) |
666 | + mp3_file = self.factory.create_file( |
667 | + os.path.join(fs.DIR_TEST_DATA_AUDIO, |
668 | + test_data.get('mp3_file').file)) |
669 | + ogg_file = self.factory.create_file( |
670 | + os.path.join(fs.DIR_TEST_DATA_AUDIO, |
671 | + test_data.get('ogg_file').file)) |
672 | + |
673 | + albums_dir, album_mp3_dir, album_ogg_dir = \ |
674 | + self.prepare_music_albums(mp3_file, ogg_file) |
675 | |
676 | # Copy the albums directory from the temporal dir in the ubuntu host |
677 | # machine to the dir which maps the music dir in the device |
678 | - device_mtp_albums_path = self.get_device_mtp_path(MUSIC, albums_name) |
679 | - self.remote_helper.copy_dir(albums_dir, device_mtp_albums_path) |
680 | + mtp_albums_path = self.mtp_helper.get_mtp_path(fs.DIR_MUSIC, |
681 | + albums_dir.name) |
682 | + albums_dir.remote_copy(mtp_albums_path) |
683 | |
684 | # Verify the albums have ben copied to the music folder |
685 | - copied_albums = self.verify_dir_copied(MUSIC_DIR, albums_name) |
686 | + albums_dir.local_dst_path = os.path.join(fs.DIR_HOME_MUSIC, |
687 | + albums_dir.name) |
688 | + self.assertTrue(os.path.isdir(albums_dir.local_dst_path)) |
689 | |
690 | - copied_album_mp3 = os.path.join(copied_albums, album_mp3_name) |
691 | - self.verify_songs(src_mp3_file, songs_album_mp3, copied_album_mp3, |
692 | + dst_path = os.path.join(albums_dir.local_dst_path, album_mp3_dir.name) |
693 | + self.verify_songs(mp3_file, songs_album_mp3, dst_path, |
694 | test_data.get('mp3_file').album) |
695 | |
696 | - copied_album_ogg = os.path.join(copied_albums, album_ogg_name) |
697 | - self.verify_songs(src_ogg_file, songs_album_ogg, copied_album_ogg, |
698 | + dst_path = os.path.join(albums_dir.local_dst_path, album_ogg_dir.name) |
699 | + self.verify_songs(ogg_file, songs_album_ogg, dst_path, |
700 | test_data.get('ogg_file').album) |
701 | |
702 | def test_copy_large_number_of_files(self): |
703 | @@ -336,53 +178,43 @@ |
704 | original. |
705 | """ |
706 | amount = 100 |
707 | - src_file_name = test_data.get('text_file') |
708 | - src_file = os.path.join(fs.DIR_TEST_DATA_TEXT, src_file_name) |
709 | + myfile = self.factory.create_file( |
710 | + os.path.join(fs.DIR_TEST_DATA_TEXT, test_data.get('text_file'))) |
711 | |
712 | # Create the dir to store the files in the host machine |
713 | - (dir_name, dir_path) = self.create_remote_dir(TEMP_DIR) |
714 | - self.addCleanup(self.remote_helper.remove_dir, dir_path) |
715 | + mydir = self.factory.create_remote_dir() |
716 | |
717 | # Copy the src file to the ubuntu host machine |
718 | - dst_tmp_file = self.copy_file_to_remote_host(src_file, TEMP_DIR) |
719 | + myfile.send_to_host(fs.DIR_TEMP) |
720 | |
721 | # Replicate the src file 100 times |
722 | - original_files = [src_file_name + "_" + str(i) for i in range(amount)] |
723 | - self.replicate_file(dst_tmp_file, dir_path, original_files) |
724 | + original_files = [myfile.name + "_" + str(i) for i in range(amount)] |
725 | + self.mtp_helper.replicate_file(myfile, mydir, original_files) |
726 | |
727 | # Copy the directory from the temporal dir in the ubuntu host |
728 | # machine to the dir which maps the documents dir in the device |
729 | - device_mtp_dir_path = self.get_device_mtp_path(DOCS, dir_name) |
730 | - logger.info("Copying remote files to mtp directory from {src_path} to " |
731 | - "{mtp_path}".format(src_path=dir_path, |
732 | - mtp_path=device_mtp_dir_path)) |
733 | - self.remote_helper.copy_dir(dir_path, device_mtp_dir_path) |
734 | + mydir.remote_copy(self.mtp_helper.get_mtp_path(fs.DIR_DOCUMENTS, |
735 | + mydir.name)) |
736 | |
737 | # Verify the files have ben copied correctly to the destiation |
738 | - copied_dir = self.verify_dir_copied(DOCS_DIR, dir_name) |
739 | - self.verify_copied_files(src_file, original_files, copied_dir) |
740 | + mydir.local_dst_path = os.path.join(fs.DIR_HOME_DOCUMENTS, mydir.name) |
741 | + self.assertTrue(os.path.isdir(mydir.local_dst_path)) |
742 | + self.verify_copied_files(myfile, original_files, mydir.local_dst_path) |
743 | |
744 | def _test_copy_big_file(self, kb=0, mb=0, gb=0): |
745 | # Create the remote file with random content and get the sha1 digest |
746 | - file_name = fs.get_random_string() + ".tmp" |
747 | - file_path = os.path.join(TEMP_DIR, file_name) |
748 | - |
749 | - self.remote_helper.create_random_file(file_path, kb=kb, mb=mb, gb=gb) |
750 | - self.addCleanup(self.remote_helper.remove_file, file_path) |
751 | - file_sha1 = self.remote_helper.get_sha1(file_path).strip() |
752 | - |
753 | + file = self.factory.create_remote_file(ext='.tmp', kb=kb, mb=mb, gb=gb) |
754 | # Copy the directory from the temporal dir in the ubuntu host |
755 | # machine to the dir which maps the documents dir in the device |
756 | - device_mtp_dst_path = self.get_device_mtp_path(DOCS, file_name) |
757 | - logger.info("Copying remote files to mtp directory from {src_path} to " |
758 | - "{mtp_path}".format(src_path=file_path, |
759 | - mtp_path=device_mtp_dst_path)) |
760 | - self.remote_helper.copy_file(file_path, device_mtp_dst_path) |
761 | + file.remote_copy(self.mtp_helper.get_mtp_path(fs.DIR_DOCUMENTS, |
762 | + file.name)) |
763 | |
764 | # Verify the files have ben copied correctly to the destiation |
765 | - copied_file = self.verify_file_copied(DOCS_DIR, file_name) |
766 | - copied_sha1 = fs.calculate_file_sha1(copied_file) |
767 | - self.assertEqual(file_sha1, copied_sha1) |
768 | + file.local_dst_path = os.path.join(fs.DIR_HOME_DOCUMENTS, file.name) |
769 | + self.assertTrue(os.path.isfile(file.local_dst_path)) |
770 | + |
771 | + copied_sha1 = fs.calculate_file_sha1(file.local_dst_path) |
772 | + self.assertEqual(file.sha1, copied_sha1) |
773 | |
774 | def test_copy_big_1gb_file(self): |
775 | """ Copy a big file (almost 2GB) through mtp and check the file has |
776 | @@ -415,21 +247,24 @@ |
777 | """ |
778 | |
779 | # Create random source data and calculate the sha1 digest |
780 | - song = self.create_random_file(MUSIC_DIR, ext='.mp3') |
781 | - song.remote_src_path = self.get_device_mtp_path(MUSIC, song.name) |
782 | - |
783 | - video = self.create_random_file(VIDEOS_DIR, ext='.avi') |
784 | - video.remote_src_path = self.get_device_mtp_path(VIDEOS, video.name) |
785 | - |
786 | - picture = self.create_random_file(PICTURES_DIR, ext='.jpg') |
787 | - picture.remote_src_path = self.get_device_mtp_path(PICTURES, |
788 | - picture.name) |
789 | + song = self.factory.create_random_file(fs.DIR_HOME_MUSIC, ext='.mp3') |
790 | + song.remote_src_path = \ |
791 | + self.mtp_helper.get_mtp_path(fs.DIR_MUSIC, song.name) |
792 | + |
793 | + video = self.factory.create_random_file(fs.DIR_HOME_VIDEOS, ext='.avi') |
794 | + video.remote_src_path = \ |
795 | + self.mtp_helper.get_mtp_path(fs.DIR_VIDEOS, video.name) |
796 | + |
797 | + picture = self.factory.create_random_file(fs.DIR_HOME_PICTURES, |
798 | + ext='.jpg') |
799 | + picture.remote_src_path = \ |
800 | + self.mtp_helper.get_mtp_path(fs.DIR_PICTURES, picture.name) |
801 | |
802 | files = [song, video, picture] |
803 | |
804 | # Set destination path to files |
805 | for file in files: |
806 | - file.remote_dst_path = os.path.join(TEMP_DIR, file.name) |
807 | + file.remote_dst_path = os.path.join(fs.DIR_TEMP, file.name) |
808 | |
809 | # Copy the files from mtp to tmp directory and verify the sha1 |
810 | for file in files: |
811 | @@ -440,4 +275,4 @@ |
812 | # Remove remote files and verify the files were deleted in the device |
813 | for file in files: |
814 | self.remote_helper.remove_file(file.remote_src_path) |
815 | - self.assertFalse(os.path.isfile(file.local_path)) |
816 | + self.assertFalse(os.path.isfile(file.local_src_path)) |
PASSED: Continuous integration, rev:154 s-jenkins. ubuntu- ci:8080/ job/ubuntu- sanity- tests-ci/ 517/ s-jenkins. ubuntu- ci:8080/ job/ubuntu- sanity- tests-wily- amd64-ci/ 245 s-jenkins. ubuntu- ci:8080/ job/ubuntu- sanity- tests-wily- armhf-ci/ 246 s-jenkins. ubuntu- ci:8080/ job/ubuntu- sanity- tests-wily- i386-ci/ 245
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild: s-jenkins. ubuntu- ci:8080/ job/ubuntu- sanity- tests-ci/ 517/rebuild
http://