def test_handling_of_nonexisting_path(with_callback, existing_torrents): # Create and prepare existing torrents existing_torrents = existing_torrents(my_torrents=( ('a', 'foo', { 'creation_date': 123 }), ('b', 'bar', { 'creation_date': 456 }), ('c', 'baz', { 'creation_date': 789 }), ), ) # Create and prepare the torrent we want to generate new_content = existing_torrents.my_torrents[0] new_torrent = torf.Torrent(path=new_content.content_path) # Expect identical metainfo exp_joined_metainfo = copy.deepcopy(new_torrent.metainfo) # Reuse existing torrent reuse_torrent_path = 'path/to/nonexisting/directory' if with_callback: callback = Mock(return_value=None) return_value = new_torrent.reuse(reuse_torrent_path, callback=callback) # Confirm everything happened as expected assert return_value is False assert new_torrent.metainfo == exp_joined_metainfo assert callback.call_args_list == [ call( new_torrent, None, 0, 0, False, ComparableException( torf.ReadError(errno.ENOENT, reuse_torrent_path), ), ), ] else: exp_exception = torf.ReadError(errno.ENOENT, reuse_torrent_path) with pytest.raises(type(exp_exception), match=rf'^{re.escape(str(exp_exception))}$'): new_torrent.reuse(reuse_torrent_path) assert new_torrent.metainfo == exp_joined_metainfo
def exp_exc_files_missing(self): if not hasattr(self, '_exp_exc_files_missing'): self._exp_exc_files_missing = fuzzylist( *(ComparableException(torf.ReadError(errno.ENOENT, filepath)) for filepath in self.files_missing)) debug(f'Expected files missing: {self._exp_exc_files_missing}') return self._exp_exc_files_missing
def test_ReadError(): for cls,args,kwargs in ((err.ReadError, ('path/to/file: No such file or directory',), {}), (err.Error, (torf.ReadError(errno.ENOENT, 'path/to/file'),), {}), (err.Error, (torf.PathError('path/to/file', msg='No such file or directory'),), {}), (err.Error, ('path/to/file: No such file or directory', err.Code.READ), {}), (err.Error, ('path/to/file: No such file or directory',), {'code': err.Code.READ})): with pytest.raises(err.ReadError) as exc_info: raise cls(*args, **kwargs) assert exc_info.value.exit_code is err.Code.READ assert str(exc_info.value) == 'path/to/file: No such file or directory'
def test_callback_cancels_when_handling(cancel_condition, exp_callback_calls_count, existing_torrents, create_file): # Create and prepare existing torrents existing_torrents = existing_torrents( readable1=( ('a', 'foo', { 'creation_date': 123 }), ('b', 'bar', { 'creation_date': 456 }), ('c', 'baz', { 'creation_date': 789 }), ), # Unreadable directory unreadable=(), readable2=( ('d', 'hey', { 'private': True }), ('e', 'ho', { 'comment': 'yo' }), ('f', 'oh', { 'comment': 'oy' }), ('g', 'ohh', { 'comment': 'oyy' }), ('h', 'ohy', { 'comment': 'hoyo' }), ), ) # ReadError (directory) existing_torrents.locations['unreadable'].chmod(0o300) # ReadError (torrent file) existing_torrents.readable2[1].torrent_path.chmod(0o300) # BdecodeError data = bytearray(existing_torrents.readable2[2].torrent_path.read_bytes()) data[0] = ord('x') existing_torrents.readable2[2].torrent_path.write_bytes(data) # MetainfoError del existing_torrents.readable2[3].torrent.metainfo['info']['piece length'] existing_torrents.readable2[3].torrent.write( existing_torrents.readable2[3].torrent_path, validate=False, overwrite=True, ) # Create and prepare the torrent we want to generate new_content = existing_torrents.readable2[4].content_path new_torrent = torf.Torrent(path=new_content) exp_joined_metainfo = copy.deepcopy(new_torrent.metainfo) def callback(torrent, torrent_path, done, total, is_match, exception): if cancel_condition(torrent_path, is_match): return 'cancel' callback_wrapper = Mock(side_effect=callback) # Reuse existing torrent return_value = new_torrent.reuse(existing_torrents.location_paths, callback=callback_wrapper) # Confirm everything happened as expected assert return_value is False assert new_torrent.metainfo == exp_joined_metainfo all_callback_calls = [ call(new_torrent, str(existing_torrents.readable1[0].torrent_path), 1, 8, False, None), call(new_torrent, str(existing_torrents.readable1[1].torrent_path), 2, 8, False, None), call(new_torrent, str(existing_torrents.readable1[2].torrent_path), 3, 8, False, None), call( new_torrent, None, 3, 8, False, ComparableException( torf.ReadError( errno.EACCES, str(existing_torrents.locations['unreadable'])), ), ), call(new_torrent, str(existing_torrents.readable2[0].torrent_path), 4, 8, False, None), call( new_torrent, str(existing_torrents.readable2[1].torrent_path), 5, 8, False, ComparableException( torf.ReadError( errno.EACCES, str(existing_torrents.readable2[1].torrent_path)), ), ), call( new_torrent, str(existing_torrents.readable2[2].torrent_path), 6, 8, False, ComparableException( torf.BdecodeError( str(existing_torrents.readable2[2].torrent_path)), ), ), call( new_torrent, str(existing_torrents.readable2[3].torrent_path), 7, 8, False, ComparableException( torf.MetainfoError("Missing 'piece length' in ['info']"), ), ), call(new_torrent, str(existing_torrents.readable2[4].torrent_path), 8, 8, None, None), call(new_torrent, str(existing_torrents.readable2[4].torrent_path), 8, 8, False, None), ] assert callback_wrapper.call_args_list == all_callback_calls[: exp_callback_calls_count]
def test_exceptions(with_callback, existing_torrents): # Create and prepare existing torrents existing_torrents = existing_torrents( readable1=( ('a', 'foo', { 'creation_date': 123 }), ('b', 'bar', { 'creation_date': 456 }), ('c', 'baz', { 'creation_date': 789 }), ), unreadable=(), readable2=( ('d', 'hey', { 'private': True }), ('e', 'ho', { 'comment': 'yo' }), ('f', 'oh', { 'comment': 'oy' }), ('g', 'ohh', { 'comment': 'oyy' }), ), ) # Unreadable directory existing_torrents.locations['unreadable'].chmod(0o300) # Unreadable torrent file existing_torrents.readable2[1].torrent_path.chmod(0o300) # Nonexisting torrent file nonexisting_torrent_file = 'no/such/path.torrent' # Create and prepare the torrent we want to generate new_content = existing_torrents.readable2[2] new_torrent = torf.Torrent( path=new_content.content_path, trackers=('http://foo:1000', 'http://foo:2000'), webseeds=('http://bar:1000', ), httpseeds=('http://baz:1000', ), private=True, comment='This is a custom torrent', creation_date=123000, created_by='CREATOR', source='SRC', piece_size=8 * 1048576, randomize_infohash=True, ) # Reuse existing torrent if with_callback: # Expect the same metainfo, but with important parts copied exp_joined_metainfo = copy.deepcopy(new_torrent.metainfo) exp_joined_metainfo['info'][ 'piece length'] = new_content.torrent.metainfo['info'][ 'piece length'] exp_joined_metainfo['info']['pieces'] = new_content.torrent.metainfo[ 'info']['pieces'] callback = Mock(return_value=None) location_paths = ( nonexisting_torrent_file, ) + existing_torrents.location_paths return_value = new_torrent.reuse(location_paths, callback=callback) # Confirm everything happened as expected assert return_value is True assert new_torrent.metainfo == exp_joined_metainfo for c in callback.call_args_list: print(c) assert callback.call_args_list == [ call( new_torrent, nonexisting_torrent_file, 1, 8, False, ComparableException( torf.ReadError(errno.ENOENT, nonexisting_torrent_file), ), ), call(new_torrent, str(existing_torrents.readable1[0].torrent_path), 2, 8, False, None), call(new_torrent, str(existing_torrents.readable1[1].torrent_path), 3, 8, False, None), call(new_torrent, str(existing_torrents.readable1[2].torrent_path), 4, 8, False, None), call( new_torrent, None, 4, 8, False, ComparableException( torf.ReadError( errno.EACCES, str(existing_torrents.locations['unreadable'])), ), ), call(new_torrent, str(existing_torrents.readable2[0].torrent_path), 5, 8, False, None), call( new_torrent, str(existing_torrents.readable2[1].torrent_path), 6, 8, False, ComparableException( torf.ReadError( errno.EACCES, str(existing_torrents.readable2[1].torrent_path)), ), ), call(new_torrent, str(existing_torrents.readable2[2].torrent_path), 7, 8, None, None), call(new_torrent, str(existing_torrents.readable2[2].torrent_path), 7, 8, True, None), ] else: # Expect identical metainfo exp_joined_metainfo = copy.deepcopy(new_torrent.metainfo) exp_exception = torf.ReadError( errno.EACCES, str(existing_torrents.locations['unreadable'])) with pytest.raises(type(exp_exception), match=rf'^{re.escape(str(exp_exception))}$'): new_torrent.reuse(existing_torrents.location_paths) # Confirm everything happened as expected assert new_torrent.metainfo == exp_joined_metainfo