%PDF- %PDF-
Direktori : /usr/lib/calibre/calibre/devices/mtp/ |
Current File : //usr/lib/calibre/calibre/devices/mtp/test.py |
#!/usr/bin/env python3 __license__ = 'GPL v3' __copyright__ = '2012, Kovid Goyal <kovid at kovidgoyal.net>' __docformat__ = 'restructuredtext en' import unittest, gc, io from calibre.constants import iswindows, islinux from calibre.utils.icu import lower from calibre.devices.mtp.driver import MTP_DEVICE from calibre.devices.scanner import DeviceScanner class ProgressCallback: def __init__(self): self.count = 0 self.end_called = False def __call__(self, pos, total): if pos == total: self.end_called = True self.count += 1 class TestDeviceInteraction(unittest.TestCase): @classmethod def setUpClass(cls): cls.dev = cls.storage = None cls.dev = MTP_DEVICE(None) cls.dev.startup() cls.scanner = DeviceScanner() cls.scanner.scan() cd = cls.dev.detect_managed_devices(cls.scanner.devices) if cd is None: cls.dev.shutdown() cls.dev = None return cls.dev.open(cd, 'test_library') if cls.dev.free_space()[0] < 10*(1024**2): return cls.dev.filesystem_cache cls.storage = cls.dev.filesystem_cache.entries[0] @classmethod def tearDownClass(cls): if cls.dev is not None: cls.dev.shutdown() cls.dev = None def setUp(self): self.cleanup = [] def tearDown(self): for obj in reversed(self.cleanup): self.dev.delete_file_or_folder(obj) def check_setup(self): if self.dev is None: self.skipTest('No MTP device detected') if self.storage is None: self.skipTest('The connected device does not have enough free space') def test_folder_operations(self): ''' Test the creation of folders, duplicate folders and sub folders ''' self.check_setup() # Create a folder name = 'zzz-test-folder' folder = self.dev.create_folder(self.storage, name) self.cleanup.append(folder) self.assertTrue(folder.is_folder) self.assertEqual(folder.parent_id, self.storage.object_id) self.assertEqual(folder.storage_id, self.storage.object_id) self.assertEqual(lower(name), lower(folder.name)) # Create a sub-folder name = 'sub-folder' subfolder = self.dev.create_folder(folder, name) self.assertTrue(subfolder.is_folder) self.assertEqual(subfolder.parent_id, folder.object_id) self.assertEqual(subfolder.storage_id, self.storage.object_id) self.assertEqual(lower(name), lower(subfolder.name)) self.cleanup.append(subfolder) # Check that creating an existing folder returns that folder (case # insensitively) self.assertIs(subfolder, self.dev.create_folder(folder, 'SUB-FOLDER'), msg='Creating an existing folder did not return the existing folder') # Check that creating folders as children of files is not allowed root_file = [f for f in self.dev.filesystem_cache.entries[0].files if not f.is_folder] if root_file: with self.assertRaises(ValueError): self.dev.create_folder(root_file[0], 'sub-folder') def test_file_transfer(self): ''' Test transferring files to and from the device ''' self.check_setup() # Create a folder name = 'zzz-test-folder' folder = self.dev.create_folder(self.storage, name) self.cleanup.append(folder) self.assertTrue(folder.is_folder) self.assertEqual(folder.parent_id, self.storage.object_id) # Check simple file put/get size = 1024**2 raw = io.BytesIO(b'a'*size) raw.seek(0) name = 'test-file.txt' pc = ProgressCallback() f = self.dev.put_file(folder, name, raw, size, callback=pc) self.cleanup.append(f) self.assertEqual(f.name, name) self.assertEqual(f.size, size) self.assertEqual(f.parent_id, folder.object_id) self.assertEqual(f.storage_id, folder.storage_id) self.assertTrue(pc.end_called, msg='Progress callback not called with equal values (put_file)') self.assertTrue(pc.count > 1, msg='Progress callback only called once (put_file)') raw2 = io.BytesIO() pc = ProgressCallback() self.dev.get_mtp_file(f, raw2, callback=pc) self.assertEqual(raw.getvalue(), raw2.getvalue()) self.assertTrue(pc.end_called, msg='Progress callback not called with equal values (get_file)') self.assertTrue(pc.count > 1, msg='Progress callback only called once (get_file)') # Check file replacement raw = io.BytesIO(b'abcd') raw.seek(0) size = 4 f = self.dev.put_file(folder, name, raw, size) self.cleanup.append(f) self.assertEqual(f.name, name) self.assertEqual(f.size, size) self.assertEqual(f.parent_id, folder.object_id) self.assertEqual(f.storage_id, folder.storage_id) # Check that we get an error with replace=False raw.seek(0) with self.assertRaises(ValueError): self.dev.put_file(folder, name, raw, size, replace=False) # Check that we can put a file into the root raw.seek(0) name = 'zzz-test-file.txt' f = self.dev.put_file(self.storage, name, raw, size) self.cleanup.append(f) self.assertEqual(f.name, name) self.assertEqual(f.size, size) self.assertEqual(f.parent_id, self.storage.object_id) self.assertEqual(f.storage_id, self.storage.storage_id) raw2 = io.BytesIO() self.dev.get_mtp_file(f, raw2) self.assertEqual(raw.getvalue(), raw2.getvalue()) def measure_memory_usage(self, repetitions, func, *args, **kwargs): from calibre.utils.mem import memory gc.disable() try: start_mem = memory() for i in range(repetitions): func(*args, **kwargs) for i in range(3): gc.collect() end_mem = memory() finally: gc.enable() return end_mem - start_mem def check_memory(self, once, many, msg, factor=2): msg += ' for once: %g for many: %g'%(once, many) if once > 0: self.assertTrue(many <= once*factor, msg=msg) else: self.assertTrue(many <= 0.01, msg=msg) @unittest.skipUnless(iswindows or islinux, 'Can only test for leaks on windows and linux') def test_memory_leaks(self): ''' Test for memory leaks in the C module ''' self.check_setup() # Test device scanning used_by_one = self.measure_memory_usage(1, self.dev.detect_managed_devices, self.scanner.devices, force_refresh=True) used_by_many = self.measure_memory_usage(100, self.dev.detect_managed_devices, self.scanner.devices, force_refresh=True) self.check_memory(used_by_one, used_by_many, 'Memory consumption during device scan') # Test file transfer size = 1024*100 raw = io.BytesIO(b'a'*size) raw.seek(0) name = 'zzz-test-file.txt' def send_file(storage, name, raw, size): raw.seek(0) pc = ProgressCallback() f = self.dev.put_file(storage, name, raw, size, callback=pc) self.cleanup.append(f) del pc used_once = self.measure_memory_usage(1, send_file, self.storage, name, raw, size) used_many = self.measure_memory_usage(20, send_file, self.storage, name, raw, size) self.check_memory(used_once, used_many, 'Memory consumption during put_file:') def get_file(f): raw = io.BytesIO() pc = ProgressCallback() self.dev.get_mtp_file(f, raw, callback=pc) raw.truncate(0) del raw del pc f = self.storage.file_named(name) used_once = self.measure_memory_usage(1, get_file, f) used_many = self.measure_memory_usage(20, get_file, f) self.check_memory(used_once, used_many, 'Memory consumption during get_file:') # Test get_filesystem used_by_one = self.measure_memory_usage(1, self.dev.dev.get_filesystem, self.storage.object_id, lambda x, l:True) used_by_many = self.measure_memory_usage(5, self.dev.dev.get_filesystem, self.storage.object_id, lambda x, l: True) self.check_memory(used_by_one, used_by_many, 'Memory consumption during get_filesystem') def tests(): tl = unittest.TestLoader() # return tl.loadTestsFromName('test.TestDeviceInteraction.test_memory_leaks') return tl.loadTestsFromTestCase(TestDeviceInteraction) def run(): unittest.TextTestRunner(verbosity=2).run(tests()) if __name__ == '__main__': run()