async def setUp(self): await TriblerCoreTest.setUp(self) self.download = Download(Mock(), None) mock_handle = MockObject() mock_status = MockObject() mock_status.pieces = [True, False, True, True, False] torrent_info = MockObject() file_info = MockObject() file_info.size = 1234 torrent_info.file_at = lambda _: file_info map_file_result = MockObject() map_file_result.piece = 123 torrent_info.map_file = lambda _dummy1, _dummy2, _dummy3: map_file_result torrent_info.num_pieces = lambda: 5 mock_handle.is_valid = lambda: True mock_handle.status = lambda: mock_status mock_handle.get_torrent_info = lambda: torrent_info mock_handle.set_sequential_download = lambda _: None mock_handle.set_priority = lambda _: None mock_handle.prioritize_pieces = lambda _: None mock_handle.save_resume_data = lambda: None self.download.handle = mock_handle # Create a fake tdef self.download.tdef = MockObject() self.download.tdef.get_name = lambda: "ubuntu.iso" self.download.tdef.get_name_as_unicode = lambda: "ubuntu.iso" self.download.tdef.get_infohash = lambda: b'a' * 20 self.download.tdef.is_multifile_torrent = lambda: False self.download.config = DownloadConfig()
async def test_remove_with_files(self): """ Testing whether the API returns 200 if a download is being removed """ # Create a copy of the file, so we can remove it later source_file = TESTS_DATA_DIR / 'video.avi' tmpdir = self.temporary_directory() copied_file = tmpdir / Path(source_file).name shutil.copyfile(source_file, copied_file) video_tdef, _ = self.create_local_torrent(copied_file) dcfg = DownloadConfig() dcfg.set_dest_dir(tmpdir) download = self.session.dlmgr.start_download(tdef=video_tdef, config=dcfg) infohash = get_hex_infohash(video_tdef) while not download.handle: await sleep(0.1) await sleep(2) await self.do_request('downloads/%s' % infohash, post_data={"remove_data": True}, expected_code=200, request_type='DELETE', expected_json={ u"removed": True, u"infohash": u"c9a19e7fe5d9a6c106d6ea3c01746ac88ca3c7a5" }) while copied_file.exists(): await sleep(0.1) self.assertEqual(len(self.session.dlmgr.get_downloads()), 0) self.assertFalse(copied_file.exists())
async def hidden_seeder_session(seed_config, video_tdef): seed_config.set_libtorrent_enabled(False) seeder_session = Session(seed_config) seeder_session.upgrader_enabled = False await seeder_session.start() # Also load the tunnel community in the seeder session await load_tunnel_community_in_session(seeder_session, start_lt=True) seeder_session.tunnel_community.build_tunnels(1) dscfg_seed = DownloadConfig() dscfg_seed.set_dest_dir(TESTS_DATA_DIR) dscfg_seed.set_hops(1) upload = seeder_session.dlmgr.start_download(tdef=video_tdef, config=dscfg_seed) def seeder_state_callback(ds): """ The callback of the seeder download. For now, this only logs the state of the download that's seeder and is useful for debugging purposes. """ seeder_session.tunnel_community.monitor_downloads([ds]) d = ds.get_download() print( f"seeder: {repr(d.get_def().get_name())} {dlstatus_strings[ds.get_status()]} {ds.get_progress()}" ) return 2 upload.set_state_callback(seeder_state_callback) await upload.wait_for_status(DLSTATUS_SEEDING) yield seeder_session await seeder_session.shutdown()
async def test_set_rate_settings(enable_api, mock_dlmgr, session): """ Testing whether libtorrent rate limits works for large number without overflow error. """ dcfg = DownloadConfig() download = Mock() download.config = dcfg session.dlmgr.get_downloads = lambda: [download] extra_rate = 1024 * 1024 * 1024 # 1GB/s post_data = { 'libtorrent': { 'max_download_rate': MAX_LIBTORRENT_RATE_LIMIT + extra_rate, 'max_upload_rate': MAX_LIBTORRENT_RATE_LIMIT + extra_rate } } await do_request(session, 'settings', expected_code=200, request_type='POST', post_data=post_data) assert session.config.get_libtorrent_max_download_rate( ) == MAX_LIBTORRENT_RATE_LIMIT assert session.config.get_libtorrent_max_upload_rate( ) == MAX_LIBTORRENT_RATE_LIMIT
def create_dconfig_from_params(parameters): """ Create a download configuration based on some given parameters. Possible parameters are: - anon_hops: the number of hops for the anonymous download. 0 hops is equivalent to a plain download - safe_seeding: whether the seeding of the download should be anonymous or not (0 = off, 1 = on) - destination: the destination path of the torrent (where it is saved on disk) """ download_config = DownloadConfig() anon_hops = parameters.get('anon_hops', 0) safe_seeding = bool(parameters.get('safe_seeding', 0)) if anon_hops > 0 and not safe_seeding: return None, "Cannot set anonymous download without safe seeding enabled" if anon_hops > 0: download_config.set_hops(anon_hops) if safe_seeding: download_config.set_safe_seeding(True) if parameters.get('destination'): dest_dir = parameters['destination'] download_config.set_dest_dir(dest_dir) if 'selected_files' in parameters: download_config.set_selected_files(parameters['selected_files']) return download_config, None
async def setup_tunnel_seeder(self, hops): """ Setup the seeder. """ from tribler_core.session import Session self.seed_config = self.config.copy() self.seed_config._state_dir = self.getRootStateDir(2) self.seed_config.set_libtorrent_enabled(hops == 0) self.seed_config.set_tunnel_community_socks5_listen_ports( self.get_ports(5)) if self.session2 is None: self.session2 = Session(self.seed_config) self.session2.upgrader_enabled = False await self.session2.start() tdef = TorrentDef() tdef.add_content(TESTS_DATA_DIR / "video.avi") tdef.set_tracker("http://localhost/announce") torrentfn = self.session2.config.get_state_dir() / "gen.torrent" tdef.save(torrent_filepath=torrentfn) self.seed_tdef = tdef if hops > 0: # Safe seeding enabled self.tunnel_community_seeder = await self.load_tunnel_community_in_session( self.session2, start_lt=True) self.tunnel_community_seeder.build_tunnels(hops) else: await self.sanitize_network(self.session2) dscfg = DownloadConfig() dscfg.set_dest_dir( TESTS_DATA_DIR) # basedir of the file we are seeding dscfg.set_hops(hops) d = self.session2.dlmgr.start_download(tdef=tdef, config=dscfg) d.set_state_callback(self.seeder_state_callback)
def check_watch_folder(self): if not self.session.config.get_watch_folder_path().is_dir(): return # Make sure that we pass a str to os.walk watch_dir = str(self.session.config.get_watch_folder_path()) for root, _, files in os.walk(watch_dir): root = path_util.Path(root) for name in files: if not name.endswith(".torrent"): continue try: tdef = TorrentDef.load(root / name) if not tdef.get_metainfo(): self.cleanup_torrent_file(root, name) continue except: # torrent appears to be corrupt self.cleanup_torrent_file(root, name) continue infohash = tdef.get_infohash() if not self.session.dlmgr.download_exists(infohash): self._logger.info("Starting download from torrent file %s", name) dl_config = DownloadConfig() anon_enabled = self.session.config.get_default_anonymity_enabled() default_num_hops = self.session.config.get_default_number_hops() dl_config.set_hops(default_num_hops if anon_enabled else 0) dl_config.set_safe_seeding(self.session.config.get_default_safeseeding_enabled()) dl_config.set_dest_dir(self.session.config.get_default_destination_dir()) self.session.dlmgr.start_download(tdef=tdef, config=dl_config)
def test_user_stopped(self): dlcfg = DownloadConfig() dlcfg.set_user_stopped(False) self.assertFalse(dlcfg.get_user_stopped()) dlcfg.set_user_stopped(True) self.assertTrue(dlcfg.get_user_stopped())
def start_download(self, torrent_file=None, tdef=None, config=None, checkpoint_disabled=False, hidden=False): self._logger.debug("Starting download: filename: %s, torrent def: %s", torrent_file, tdef) # the priority of the parameters is: (1) tdef, (2) torrent_file. # so if we have tdef, and torrent_file will be ignored, and so on. if tdef is None: if torrent_file is None: raise ValueError( "Torrent file must be provided if tdef is not given") # try to get the torrent from the given torrent file tdef = TorrentDef.load(torrent_file) assert tdef is not None, "tdef MUST not be None after loading torrent" config = config or DownloadConfig() infohash = tdef.get_infohash() download = self.get_download(infohash) if download and infohash not in self.metainfo_requests: new_trackers = list( set(tdef.get_trackers_as_single_tuple()) - set(download.get_def().get_trackers_as_single_tuple())) if new_trackers: self.update_trackers(tdef.get_infohash(), new_trackers) return download # Create the destination directory if it does not exist yet try: if not config.get_dest_dir().is_dir(): os.makedirs(config.get_dest_dir()) except OSError: self._logger.error( "Unable to create the download destination directory.") if config.get_time_added() == 0: config.set_time_added(int(timemod.time())) # Create the download download = Download(self.tribler_session, tdef, dummy=self.dummy_mode) atp = download.setup(config, checkpoint_disabled=checkpoint_disabled, hidden=hidden or config.get_bootstrap_download()) # Keep metainfo downloads in self.downloads for now because we will need to remove it later, # and removing the download at this point will stop us from receiving any further alerts. if infohash not in self.metainfo_requests or self.metainfo_requests[ infohash][0] == download: self.downloads[infohash] = download if not self.dummy_mode: self.start_handle(download, atp) return download
def setup(self, config=None, hidden=False, checkpoint_disabled=False): """ Create a Download object. Used internally by Session. @param config DownloadConfig or None (in which case a new DownloadConfig() is created :returns a Deferred to which a callback can be added which returns the result of network_create_engine_wrapper. """ self.hidden = hidden self.checkpoint_disabled = checkpoint_disabled or self.dummy self.config = config or DownloadConfig( state_dir=self.session.config.get_state_dir()) self._logger.debug("Setup: %s", hexlify(self.tdef.get_infohash())) self.checkpoint() atp = { "save_path": path_util.normpath(get_default_dest_dir() / self.config.get_dest_dir()), "storage_mode": lt.storage_mode_t.storage_mode_sparse, "flags": lt.add_torrent_params_flags_t.flag_paused | lt.add_torrent_params_flags_t.flag_duplicate_is_error | lt.add_torrent_params_flags_t.flag_update_subscribe } if self.config.get_share_mode(): atp["flags"] = atp[ "flags"] | lt.add_torrent_params_flags_t.flag_share_mode if self.config.get_upload_mode(): atp["flags"] = atp[ "flags"] | lt.add_torrent_params_flags_t.flag_upload_mode resume_data = self.config.get_engineresumedata() if not isinstance(self.tdef, TorrentDefNoMetainfo): metainfo = self.tdef.get_metainfo() torrentinfo = lt.torrent_info(metainfo) atp["ti"] = torrentinfo if resume_data and isinstance(resume_data, dict): # Rewrite save_path as a global path, if it is given as a relative path if b"save_path" in resume_data and not path_util.isabs( ensure_unicode(resume_data[b"save_path"], 'utf8')): resume_data[ b"save_path"] = self.state_dir / ensure_unicode( resume_data[b"save_path"], 'utf8') atp["resume_data"] = lt.bencode(resume_data) else: atp["url"] = self.tdef.get_url( ) or "magnet:?xt=urn:btih:" + hexlify(self.tdef.get_infohash()) atp["name"] = self.tdef.get_name_as_unicode() return atp
async def channel_seeder_session(seed_config, channel_tdef): seeder_session = Session(seed_config) seeder_session.upgrader_enabled = False await seeder_session.start() dscfg_seed = DownloadConfig() dscfg_seed.set_dest_dir(TESTS_DATA_DIR / 'sample_channel') upload = seeder_session.dlmgr.start_download(tdef=channel_tdef, config=dscfg_seed) await upload.wait_for_status(DLSTATUS_SEEDING) yield seeder_session await seeder_session.shutdown()
def start_anon_download(session, seed_session, tdef, hops=1): """ Start an anonymous download in the main Tribler session. """ session.config.set_libtorrent_dht_readiness_timeout(0) dscfg = DownloadConfig() dscfg.set_dest_dir(session.config.get_state_dir()) dscfg.set_hops(hops) download = session.dlmgr.start_download(tdef=tdef, config=dscfg) session.tunnel_community.bittorrent_peers[download] = [ ("127.0.0.1", seed_session.config.get_libtorrent_port()) ] return download
async def test_multifile_torrent(self): # Achtung! This test is completely and utterly broken, as is the whole libtorrent wrapper! # Don't try to understand it, it is a legacy thing! tdef = TorrentDef() tdef.add_content(TESTS_DATA_DIR / "video.avi") tdef.set_tracker("http://tribler.org/announce") tdef.save() fake_handler = MockObject() fake_handler.is_valid = lambda: True fake_handler.status = lambda: fake_status fake_handler.set_share_mode = lambda _: None fake_handler.set_priority = lambda _: None fake_handler.set_sequential_download = lambda _: None fake_handler.resume = lambda: None fake_handler.set_max_connections = lambda _: None fake_handler.apply_ip_filter = lambda _: None fake_handler.save_resume_data = lambda: None fake_status = MockObject() fake_status.share_mode = False dl = Download(self.session, tdef) dl.set_selected_files = lambda: None dl.future_added = succeed(fake_handler) # Create a dummy download config dl.config = DownloadConfig() dl.config.set_engineresumedata({ b"save_path": path_util.abspath(self.state_dir), b"info-hash": b'\x00' * 20 }) dl.setup() dl.config.set_engineresumedata({ b"save_path": path_util.abspath(self.state_dir), b"info-hash": b'\x00' * 20 }) dl.setup() dl.config.set_engineresumedata({ b"save_path": "some_local_dir", b"info-hash": b'\x00' * 20 }) dl.setup() await dl.shutdown()
def updated_my_channel(self, tdef): """ Notify the core that we updated our channel. """ with db_session: my_channel = self.session.mds.ChannelMetadata.get( infohash=database_blob(tdef.get_infohash())) if (my_channel and my_channel.status == COMMITTED and not self.session.dlmgr.download_exists( bytes(my_channel.infohash))): dcfg = DownloadConfig( state_dir=self.session.config.get_state_dir()) dcfg.set_dest_dir(self.session.mds.channels_dir) dcfg.set_channel_download(True) return self.session.dlmgr.start_download(tdef=tdef, config=dcfg)
async def get_metainfo(self, infohash, timeout=30, hops=None, url=None): """ Lookup metainfo for a given infohash. The mechanism works by joining the swarm for the infohash connecting to a few peers, and downloading the metadata for the torrent. :param infohash: The (binary) infohash to lookup metainfo for. :param timeout: A timeout in seconds. :param hops: the number of tunnel hops to use for this lookup. If None, use config default. :param url: Optional URL. Can contain trackers info, etc. :return: The metainfo """ infohash_hex = hexlify(infohash) if infohash in self.metainfo_cache: self._logger.info('Returning metainfo from cache for %s', infohash_hex) return self.metainfo_cache[infohash]['meta_info'] self._logger.info('Trying to fetch metainfo for %s', infohash_hex) if infohash in self.metainfo_requests: download = self.metainfo_requests[infohash][0] self.metainfo_requests[infohash][1] += 1 elif infohash in self.downloads: download = self.downloads[infohash] else: tdef = TorrentDefNoMetainfo(infohash, 'metainfo request', url=url) dcfg = DownloadConfig() dcfg.set_hops(self.tribler_session.config.get_default_number_hops() if hops is None else hops) dcfg.set_upload_mode(True) # Upload mode should prevent libtorrent from creating files dcfg.set_dest_dir(self.metadata_tmpdir) try: download = self.start_download(tdef=tdef, config=dcfg, hidden=True, checkpoint_disabled=True) except TypeError: return self.metainfo_requests[infohash] = [download, 1] try: metainfo = download.tdef.get_metainfo() or await wait_for(shield(download.future_metainfo), timeout) self._logger.info('Successfully retrieved metainfo for %s', infohash_hex) self.metainfo_cache[infohash] = {'time': timemod.time(), 'meta_info': metainfo} except (CancelledError, asyncio.TimeoutError): metainfo = None self._logger.info('Failed to retrieve metainfo for %s', infohash_hex) if infohash in self.metainfo_requests: self.metainfo_requests[infohash][1] -= 1 if self.metainfo_requests[infohash][1] <= 0: await self.remove_download(download, remove_content=True) self.metainfo_requests.pop(infohash) return metainfo
async def test_seeding(enable_libtorrent, video_seeder_session, video_tdef, session, tmpdir): """ Test whether a torrent is correctly seeded """ dscfg = DownloadConfig() dscfg.set_dest_dir(tmpdir) download = session.dlmgr.start_download(tdef=video_tdef, config=dscfg) download.add_peer( ("127.0.0.1", video_seeder_session.config.get_libtorrent_port())) await download.wait_for_status(DLSTATUS_SEEDING) with open(tmpdir / "video.avi", "rb") as f: realdata = f.read() with open(TESTS_DATA_DIR / 'video.avi', "rb") as f: expdata = f.read() assert realdata == expdata
async def add_torrent(self, piece_length=1024): [srchandle, sourcefn] = mkstemp(dir=TESTS_DIR) data = b''.join([i.to_bytes(2, byteorder='big') for i in range(1000)]) os.write(srchandle, data) os.close(srchandle) tdef = TorrentDef() tdef.add_content(sourcefn) tdef.set_piece_length(piece_length) torrentfn = self.session.config.get_state_dir() / "gen.torrent" tdef.save(torrentfn) dscfg = DownloadConfig() destdir = Path(sourcefn).parent dscfg.set_dest_dir(destdir) download = self.session.dlmgr.start_download(tdef=tdef, config=dscfg) await download.wait_for_status(DLSTATUS_SEEDING) return tdef.get_infohash(), data
async def add_torrent(self): [srchandle, sourcefn] = mkstemp(dir=TESTS_DIR) self.data = b'\xFF' * self.size # pylint: disable=attribute-defined-outside-init os.write(srchandle, self.data) os.close(srchandle) tdef = TorrentDef() tdef.add_content(sourcefn) tdef.set_piece_length(self.piece_len) torrentfn = self.session.config.get_state_dir() / "gen.torrent" tdef.save(torrentfn) dscfg = DownloadConfig() destdir = Path(sourcefn).parent dscfg.set_dest_dir(destdir) self.download = self.session.dlmgr.start_download(tdef=tdef, config=dscfg) # pylint: disable=attribute-defined-outside-init await self.download.wait_for_status(DLSTATUS_SEEDING) self.infohash = tdef.get_infohash() # pylint: disable=attribute-defined-outside-init
def __init__(self, config_dir, dht=None): super(Bootstrap, self).__init__() self._logger = logging.getLogger(self.__class__.__name__) self.dcfg = DownloadConfig(state_dir=config_dir) self.dcfg.set_bootstrap_download(True) self.bootstrap_dir = config_dir / 'bootstrap' if not self.bootstrap_dir.exists(): os.mkdir(self.bootstrap_dir) self.dcfg.set_dest_dir(self.bootstrap_dir) self.dcfg.set_safe_seeding(True) self.bootstrap_file = self.bootstrap_dir / "bootstrap.blocks" self.dht = dht self.bootstrap_finished = False self.infohash = None self.download = None self.bootstrap_nodes = {} self.register_task('fetch_bootstrap_peers', self.fetch_bootstrap_peers, interval=5)
async def download_channel(self, channel): """ Download a channel with a given infohash and title. :param channel: The channel metadata ORM object. """ metainfo = await self.session.dlmgr.get_metainfo(bytes( channel.infohash), timeout=60, hops=0) if metainfo is None: # Timeout looking for the channel metainfo. Probably, there are no seeds. # TODO: count the number of tries we had with the channel, so we can stop trying eventually return try: if metainfo[b'info'][b'name'].decode('utf-8') != channel.dirname: # Malformed channel # TODO: stop trying to download this channel until it is updated with a new infohash return except (KeyError, TypeError): return dcfg = DownloadConfig(state_dir=self.session.config.get_state_dir()) dcfg.set_dest_dir(self.session.mds.channels_dir) dcfg.set_channel_download(True) tdef = TorrentDef(metainfo=metainfo) download = self.session.dlmgr.start_download(tdef=tdef, config=dcfg, hidden=True) try: await download.future_finished except CancelledError: pass else: self.channels_processing_queue[channel.infohash] = ( PROCESS_CHANNEL_DIR, channel) return download
async def test_set_settings(enable_api, mock_dlmgr, session): """ Testing whether settings in the API can be successfully set """ dcfg = DownloadConfig() download = Mock() download.config = dcfg session.dlmgr.get_downloads = lambda: [download] post_data = { 'download_defaults': { 'seeding_mode': 'ratio', 'seeding_ratio': 3, 'seeding_time': 123 } } await do_request(session, 'settings', expected_code=200, request_type='POST', post_data=post_data) assert session.config.get_seeding_mode() == 'ratio' assert session.config.get_seeding_ratio() == 3 assert session.config.get_seeding_time() == 123
def test_downloadconfig(self): dlcfg = DownloadConfig() self.assertIsInstance(dlcfg.get_dest_dir(), Path) dlcfg.set_dest_dir(self.session_base_dir) self.assertEqual(dlcfg.get_dest_dir(), self.session_base_dir) dlcfg.set_hops(4) self.assertEqual(dlcfg.get_hops(), 4) dlcfg.set_safe_seeding(False) self.assertFalse(dlcfg.get_safe_seeding()) dlcfg.set_selected_files([1]) self.assertEqual(dlcfg.get_selected_files(), [1]) dlcfg.set_channel_download(True) self.assertTrue(dlcfg.get_channel_download()) dlcfg.set_add_to_channel(True) self.assertTrue(dlcfg.get_add_to_channel()) dlcfg.set_bootstrap_download(True) self.assertTrue(dlcfg.get_bootstrap_download())
async def test_set_settings(self): """ Testing whether settings in the API can be successfully set """ dcfg = DownloadConfig() download = MockObject() download.config = dcfg self.session.dlmgr.get_downloads = lambda: [download] post_data = { 'download_defaults': { 'seeding_mode': 'ratio', 'seeding_ratio': 3, 'seeding_time': 123 } } await self.do_request('settings', expected_code=200, request_type='POST', post_data=post_data) self.assertEqual(self.session.config.get_seeding_mode(), 'ratio') self.assertEqual(self.session.config.get_seeding_ratio(), 3) self.assertEqual(self.session.config.get_seeding_time(), 123)
async def create_torrent(self, request): parameters = await request.json() params = {} if 'files' in parameters and parameters['files']: file_path_list = [ ensure_unicode(f, 'utf-8') for f in parameters['files'] ] else: return RESTResponse({"error": "files parameter missing"}, status=HTTP_BAD_REQUEST) if 'description' in parameters and parameters['description']: params['comment'] = parameters['description'] if 'trackers' in parameters and parameters['trackers']: tracker_url_list = parameters['trackers'] params['announce'] = tracker_url_list[0] params['announce-list'] = tracker_url_list name = 'unknown' if 'name' in parameters and parameters['name']: name = parameters['name'] params['name'] = name export_dir = None if 'export_dir' in parameters and parameters['export_dir']: export_dir = Path(parameters['export_dir']) from tribler_core.version import version_id params['created by'] = '%s version: %s' % ('Tribler', version_id) params['nodes'] = False params['httpseeds'] = False params['encoding'] = False params['piece length'] = 0 # auto try: result = await self.session.dlmgr.create_torrent_file( file_path_list, recursive_bytes(params)) except (IOError, UnicodeDecodeError, RuntimeError) as e: self._logger.exception(e) return return_handled_exception(request, e) metainfo_dict = bdecode_compat(result['metainfo']) if export_dir and export_dir.exists(): save_path = export_dir / ("%s.torrent" % name) with open(save_path, "wb") as fd: fd.write(result['metainfo']) # Download this torrent if specified if 'download' in request.query and request.query[ 'download'] and request.query['download'] == "1": download_config = DownloadConfig() download_config.set_dest_dir(result['base_path'] if len( file_path_list) == 1 else result['base_dir']) try: self.session.dlmgr.start_download( tdef=TorrentDef(metainfo_dict), config=download_config) except DuplicateDownloadException: self._logger.warning( "The created torrent is already being downloaded.") return RESTResponse( json.dumps({ "torrent": base64.b64encode(result['metainfo']).decode('utf-8') }))
def test_downloadconfig_copy(self): dlcfg = DownloadConfig() dlcfg_copy = dlcfg.copy() self.assertEqual(dlcfg_copy.get_hops(), 0) self.assertEqual(dlcfg_copy.state_dir, dlcfg.state_dir)
def test_download_save_load(self): dlcfg = DownloadConfig() file_path = self.session_base_dir / "downloadconfig.conf" dlcfg.write(file_path) dlcfg.load(file_path)
def test_download_load_corrupt(self): dlcfg = DownloadConfig() dlcfg.load(self.CONFIG_FILES_DIR / "corrupt_download_config.conf")
def download_config(): return DownloadConfig()
async def test_download(session, mock_dlmgr, test_tdef): download = Download(session, test_tdef) download.config = DownloadConfig(state_dir=session.config.get_state_dir()) download.infohash = hexlify(test_tdef.get_infohash()) yield download await download.shutdown()