class Core(CorePluginBase): def __init__(self, name): """Used for tests only""" if name is not "test": super(Core, self).__init__(name) else: # To avoid warnings when running tests self._component_name = name def enable(self, config=None): self.log = yarss2.util.logger.Logger() self.torrent_handler = TorrentHandler(self.log) if config is None: self.yarss_config = YARSSConfig(self.log) else: self.yarss_config = config self.rssfeed_scheduler = RSSFeedScheduler(self.yarss_config, self.log) self.rssfeed_scheduler.enable_timers() self.log.info("Enabled YaRSS2 %s" % yarss2.util.common.get_version()) def disable(self): self.yarss_config.save() self.rssfeed_scheduler.disable_timers() def update(self): pass @export def initiate_rssfeed_update(self, rssfeed_key, subscription_key=None): return self.rssfeed_scheduler.queue_rssfeed_update(rssfeed_key, subscription_key=subscription_key) @export def get_config(self): "Returns the config dictionary" return self.yarss_config.get_config() @export def save_email_configurations(self, email_configurations): conf = {"email_configurations": email_configurations} try: self.yarss_config.set_config(conf) except ValueError as (v): self.log.error("Failed to save email configurations:" + str(v)) @export def save_subscription(self, dict_key=None, subscription_data=None, delete=False): """Saves the subscription in subscription_data. If subscription_data is None and delete=True, delete subscription with key==dict_key """ if delete: if subscription_data is not None: self.log.warn("save_subscription called with delete=True, but rssfeed_data is not None!") else: self.log.info("Deleting Subscription '%s'" % self.yarss_config.get_config()["subscriptions"][dict_key]["name"]) try: return self.yarss_config.generic_save_config("subscriptions", dict_key=dict_key, data_dict=subscription_data, delete=delete) except ValueError as (v): self.log.error("Failed to save subscription:" + str(v)) return None @export def save_rssfeed(self, dict_key=None, rssfeed_data=None, delete=False): """Saves the rssfeed in rssfeed_data. If rssfeed_data is None and delete=True, delete rssfeed with key==dict_key """ try: if delete: if rssfeed_data is not None: self.log.warn("save_rssfeed called with delete=True, but rssfeed_data is not None!") else: self.log.info("Stopping and deleting RSS Feed '%s'" % self.yarss_config.get_config()["rssfeeds"][dict_key]["name"]) config = self.yarss_config.generic_save_config("rssfeeds", dict_key=dict_key, data_dict=rssfeed_data, delete=delete) if delete is True: self.rssfeed_scheduler.delete_timer(dict_key) # Successfully saved rssfeed, check if timer was changed elif config: if self.rssfeed_scheduler.set_timer(rssfeed_data["key"], rssfeed_data["update_interval"]): self.log.info("Scheduled RSS Feed '%s' with interval %s" % (rssfeed_data["name"], rssfeed_data["update_interval"])) return config except ValueError as (v): self.log.error("Failed to save rssfeed:" + str(v)) @export def save_cookie(self, dict_key=None, cookie_data=None, delete=False): """Save cookie to config. If cookie_data is None and delete=True, delete cookie with key==dict_key""" if cookie_data: if type(cookie_data["value"]) is not dict: self.log.error("Cookie value must be a dictionary!") return None try: return self.yarss_config.generic_save_config("cookies", dict_key=dict_key, data_dict=cookie_data, delete=delete) except ValueError as (v): self.log.error("Failed to save cookie:" + str(v)) @export def save_email_message(self, dict_key=None, message_data=None, delete=False): """Save email message to config. If message_data is None, delete message with key==dict_key""" try: return self.yarss_config.generic_save_config("email_messages", dict_key=dict_key, data_dict=message_data, delete=delete) except ValueError as (v): self.log.error("Failed to save email message:" + str(v)) @export def add_torrent(self, torrent_info): site_cookies_dict = get_matching_cookies_dict(self.yarss_config.get_config()["cookies"], torrent_info["link"]) torrent_info["site_cookies_dict"] = site_cookies_dict torrent_download = self.torrent_handler.add_torrent(torrent_info) return torrent_download.to_dict() @export def get_path_completion(self, value): """ Returns the available path completions for the input value. """ return yarss2.util.common.get_path_completion(value)
class RSSFeedSchedulerTestCase(unittest.TestCase): def setUp(self): # NOQA self.rssfeeds = test_common.get_default_rssfeeds(5) self.rssfeeds["0"]["update_interval"] = 1 self.rssfeeds["1"]["update_interval"] = 3 self.rssfeeds["2"]["update_interval"] = 10 self.rssfeeds["3"]["update_interval"] = 30 self.rssfeeds["4"]["update_interval"] = 120 self.config = test_common.get_test_config() self.config.set_config({ "rssfeeds": self.rssfeeds, "email_configurations": { "send_email_on_torrent_events": False } }) self.scheduler = RSSFeedScheduler(self.config, log) test_component = TestComponent() self.scheduler.torrent_handler.download_torrent_file = test_component.download_torrent_file self.scheduler.enable_timers() def tearDown(self): # NOQA # Must stop loopingcalls or test fails self.scheduler.disable_timers() def test_enable_timers(self): # Now verify the timers for key in self.scheduler.rssfeed_timers.keys(): # Is the timer running? self.assertTrue( self.scheduler.rssfeed_timers[key]["timer"].running) # Does the timer have the correct interval? interval = self.scheduler.rssfeed_timers[key]["timer"].interval self.assertEquals(self.rssfeeds[key]["update_interval"] * 60, interval) self.assertEquals( self.rssfeeds[key]["update_interval"], self.scheduler.rssfeed_timers[key]["update_interval"]) def test_disable_timers(self): self.scheduler.disable_timers() # Now verify that the timers have been stopped for key in self.scheduler.rssfeed_timers.keys(): # Is the timer running? self.assertFalse( self.scheduler.rssfeed_timers[key]["timer"].running) def test_delete_timer(self): # Delete timer self.assertTrue(self.scheduler.delete_timer("0")) self.assertFalse(self.scheduler.delete_timer("-1")) self.assertEquals(len(self.scheduler.rssfeed_timers.keys()), 4) self.assertFalse("0" in self.scheduler.rssfeed_timers) def test_reschedule_timer(self): # Change interval to 60 minutes self.assertTrue(self.scheduler.set_timer("0", 60)) interval = self.scheduler.rssfeed_timers["0"]["timer"].interval self.assertEquals(60 * 60, interval) self.assertEquals( self.scheduler.rssfeed_timers["0"]["update_interval"], 60) def test_schedule_timer(self): # Add new timer (with key "5") with interval 60 minutes self.assertTrue(self.scheduler.set_timer("5", 60)) # Verify timer values interval = self.scheduler.rssfeed_timers["5"]["timer"].interval self.assertEquals(60 * 60, interval) self.assertEquals( self.scheduler.rssfeed_timers["5"]["update_interval"], 60) # Should now be 6 timers self.assertEquals(len(self.scheduler.rssfeed_timers.keys()), 6) def test_rssfeed_update_handler(self): subscription = yarss2.yarss_config.get_fresh_subscription_config( rssfeed_key="0", key="0") self.config.set_config({"subscriptions": {"0": subscription}}) # Check that last_update changes old_last_update = self.rssfeeds["0"]["last_update"] # Run the rssfeed with key 0 self.scheduler.rssfeed_update_handler("0") self.assertNotEquals(old_last_update, self.rssfeeds["0"]["last_update"]) old_last_update = self.rssfeeds["0"]["last_update"] # Run the subscription with key 0 like when the user runs it manually self.scheduler.rssfeed_update_handler(None, "0") # last_update should not have changed self.assertEquals(old_last_update, self.rssfeeds["0"]["last_update"]) def test_rssfeed_update_handler_exception(self): subscription = yarss2.yarss_config.get_fresh_subscription_config( rssfeed_key="0", key="0") self.config.set_config({"subscriptions": {"0": subscription}}) self.scheduler.rssfeed_update_handler_safe("0") # Run the rssfeed with invalid key self.assertRaises(KeyError, self.scheduler.rssfeed_update_handler, 1) # Safe function should not raise exception self.assertFalse(self.scheduler.rssfeed_update_handler_safe(1)) def test_ttl_value_updated(self): config = test_common.get_test_config_dict() config["rssfeeds"]["0"]["update_interval"] = 30 config["rssfeeds"]["0"]["obey_ttl"] = True config["rssfeeds"]["0"]["url"] = yarss2.util.common.get_resource( test_common.testdata_rssfeed_filename, path="tests") yarss_config = test_common.get_test_config() yarss_config.set_config(config) self.scheduler.disable_timers() self.scheduler.yarss_config = yarss_config self.scheduler.enable_timers() def add_torrents_pass(*arg): pass self.scheduler.add_torrents_func = add_torrents_pass # Run the rssfeed with key 0 self.scheduler.rssfeed_update_handler("0") # Verify that update_interval of rssfeed in config was updated self.assertEquals( yarss_config.get_config()["rssfeeds"]["0"]["update_interval"], 60) # Verify that update_interval of the timer was updated self.assertEquals( self.scheduler.rssfeed_timers["0"]["update_interval"], 60) self.scheduler.disable_timers() def test_rssfeed_update_queue(self): """Tests that the add_torrents_func is called the correct number of times, and that add_torrents_func is running in the main thread. """ # Don't use the loopingcall, so disable just to avoid any trouble self.scheduler.disable_timers() self.config.set_config(test_common.get_test_config_dict()) add_torrents_count = [] main_thread = threading.current_thread() def add_torrents_cb(*arg): self.assertEquals( main_thread, threading.current_thread(), "add_torrents must be called from the main thread!") add_torrents_count.append(0) self.scheduler.add_torrents_func = add_torrents_cb d_first = self.scheduler.queue_rssfeed_update(rssfeed_key="0") self.scheduler.queue_rssfeed_update(subscription_key="1") self.scheduler.queue_rssfeed_update(rssfeed_key="1") d_last = self.scheduler.queue_rssfeed_update(rssfeed_key="2") def verify_callback_count(args): self.assertEquals(len(add_torrents_count), 3) return DeferredList([d_first, d_last]).addBoth(verify_callback_count)
class Core(CorePluginBase): def __init__(self, name): """Used for tests only""" if name is not "test": super(Core, self).__init__(name) else: # To avoid warnings when running tests self._component_name = name def enable(self, config=None): self.log = yarss2.util.logger.Logger() self.torrent_handler = TorrentHandler(self.log) if config is None: self.yarss_config = YARSSConfig(self.log) else: self.yarss_config = config self.rssfeed_scheduler = RSSFeedScheduler(self.yarss_config, self.log) self.rssfeed_scheduler.enable_timers() self.log.info("Enabled YaRSS2 %s" % yarss2.util.common.get_version()) def disable(self): self.yarss_config.save() self.rssfeed_scheduler.disable_timers() def update(self): pass @export def initiate_rssfeed_update(self, rssfeed_key, subscription_key=None): return self.rssfeed_scheduler.queue_rssfeed_update( rssfeed_key, subscription_key=subscription_key) @export def get_config(self): "Returns the config dictionary" return self.yarss_config.get_config() @export def save_general_config(self, conf): conf = {"general": conf} try: self.yarss_config.set_config(conf) except ValueError as (v): self.log.error("Failed to save general configurations:" + str(v)) @export def save_email_configurations(self, email_configurations): conf = {"email_configurations": email_configurations} try: self.yarss_config.set_config(conf) except ValueError as (v): self.log.error("Failed to save email configurations:" + str(v)) @export def save_subscription(self, dict_key=None, subscription_data=None, delete=False): """Saves the subscription in subscription_data. If subscription_data is None and delete=True, delete subscription with key==dict_key """ if delete: if subscription_data is not None: self.log.warn( "save_subscription called with delete=True, but rssfeed_data is not None!" ) else: self.log.info("Deleting Subscription '%s'" % self.yarss_config.get_config()["subscriptions"] [dict_key]["name"]) try: return self.yarss_config.generic_save_config( "subscriptions", dict_key=dict_key, data_dict=subscription_data, delete=delete) except ValueError as (v): self.log.error("Failed to save subscription:" + str(v)) return None @export def save_rssfeed(self, dict_key=None, rssfeed_data=None, delete=False): """Saves the rssfeed in rssfeed_data. If rssfeed_data is None and delete=True, delete rssfeed with key==dict_key """ try: if delete: if rssfeed_data is not None: self.log.warn( "save_rssfeed called with delete=True, but rssfeed_data is not None!" ) else: self.log.info("Stopping and deleting RSS Feed '%s'" % self.yarss_config.get_config()["rssfeeds"] [dict_key]["name"]) config = self.yarss_config.generic_save_config( "rssfeeds", dict_key=dict_key, data_dict=rssfeed_data, delete=delete) if delete is True: self.rssfeed_scheduler.delete_timer(dict_key) # Successfully saved rssfeed, check if timer was changed elif config: if self.rssfeed_scheduler.set_timer( rssfeed_data["key"], rssfeed_data["update_interval"], rssfeed_data["update_on_startup"]): self.log.info("Scheduled RSS Feed '%s' with interval %s" % (rssfeed_data["name"], rssfeed_data["update_interval"])) return config except ValueError as (v): self.log.error("Failed to save rssfeed:" + str(v)) @export def save_cookie(self, dict_key=None, cookie_data=None, delete=False): """Save cookie to config. If cookie_data is None and delete=True, delete cookie with key==dict_key""" if cookie_data: if type(cookie_data["value"]) is not dict: self.log.error("Cookie value must be a dictionary!") return None try: return self.yarss_config.generic_save_config("cookies", dict_key=dict_key, data_dict=cookie_data, delete=delete) except ValueError as (v): self.log.error("Failed to save cookie:" + str(v)) @export def save_email_message(self, dict_key=None, message_data=None, delete=False): """Save email message to config. If message_data is None, delete message with key==dict_key""" try: return self.yarss_config.generic_save_config( "email_messages", dict_key=dict_key, data_dict=message_data, delete=delete) except ValueError as (v): self.log.error("Failed to save email message:" + str(v)) @export def send_test_email(self, email_key): """ Send a test email """ self.email_config = self.yarss_config.get_config().get( 'email_configurations', {}) self.email_messages = self.yarss_config.get_config().get( 'email_messages', {}) torrents = ["Torrent title"] return send_torrent_email( self.email_config, self.email_messages[email_key], subscription_data={"name": "Test subscription"}, torrent_name_list=torrents, deferred=True) @export def add_torrent(self, torrent_info): site_cookies_dict = get_matching_cookies_dict( self.yarss_config.get_config()["cookies"], torrent_info["link"]) torrent_info["site_cookies_dict"] = site_cookies_dict if "rssfeed_key" in torrent_info: rssfeed_data = self.yarss_config.get_config()["rssfeeds"][ torrent_info["rssfeed_key"]] torrent_info["user_agent"] = get_user_agent( rssfeed_data=rssfeed_data) torrent_download = self.torrent_handler.add_torrent(torrent_info) return torrent_download.to_dict() @export def get_completion_paths(self, value): """ Returns the available path completions for the input value. """ return yarss2.util.common.get_completion_paths(value)
class RSSFeedSchedulerTestCase(unittest.TestCase): def setUp(self): self.rssfeeds = common.get_default_rssfeeds(5) self.rssfeeds["0"]["update_interval"] = 1 self.rssfeeds["1"]["update_interval"] = 3 self.rssfeeds["2"]["update_interval"] = 10 self.rssfeeds["3"]["update_interval"] = 30 self.rssfeeds["4"]["update_interval"] = 120 self.config = common.get_test_config() self.config.set_config({"rssfeeds": self.rssfeeds, "email_configurations": {"send_email_on_torrent_events": False} }) self.scheduler = RSSFeedScheduler(self.config, log) test_component = TestComponent() self.scheduler.torrent_handler.download_torrent_file = test_component.download_torrent_file self.scheduler.enable_timers() def tearDown(self): # Must stop loopingcalls or test fails self.scheduler.disable_timers() def test_enable_timers(self): # Now verify the timers for key in self.scheduler.rssfeed_timers.keys(): # Is the timer running? self.assertTrue(self.scheduler.rssfeed_timers[key]["timer"].running) # Does the timer have the correct interval? interval = self.scheduler.rssfeed_timers[key]["timer"].interval self.assertEquals(self.rssfeeds[key]["update_interval"] * 60, interval) self.assertEquals(self.rssfeeds[key]["update_interval"], self.scheduler.rssfeed_timers[key]["update_interval"]) def test_disable_timers(self): self.scheduler.disable_timers() # Now verify that the timers have been stopped for key in self.scheduler.rssfeed_timers.keys(): # Is the timer running? self.assertFalse(self.scheduler.rssfeed_timers[key]["timer"].running) def test_delete_timer(self): # Delete timer self.assertTrue(self.scheduler.delete_timer("0")) self.assertFalse(self.scheduler.delete_timer("-1")) self.assertEquals(len(self.scheduler.rssfeed_timers.keys()), 4) self.assertFalse(self.scheduler.rssfeed_timers.has_key("0")) def test_reschedule_timer(self): # Change interval to 60 minutes self.assertTrue(self.scheduler.set_timer("0", 60)) interval = self.scheduler.rssfeed_timers["0"]["timer"].interval self.assertEquals(60 * 60, interval) self.assertEquals(self.scheduler.rssfeed_timers["0"]["update_interval"], 60) def test_schedule_timer(self): # Add new timer (with key "5") with interval 60 minutes self.assertTrue(self.scheduler.set_timer("5", 60)) # Verify timer values interval = self.scheduler.rssfeed_timers["5"]["timer"].interval self.assertEquals(60 * 60, interval) self.assertEquals(self.scheduler.rssfeed_timers["5"]["update_interval"], 60) # Should now be 6 timers self.assertEquals(len(self.scheduler.rssfeed_timers.keys()), 6) def test_rssfeed_update_handler(self): subscription = yarss2.yarss_config.get_fresh_subscription_config(rssfeed_key="0", key="0") self.config.set_config({"subscriptions": {"0": subscription} }) # Check that last_update changes old_last_update = self.rssfeeds["0"]["last_update"] # Run the rssfeed with key 0 self.scheduler.rssfeed_update_handler("0") self.assertNotEquals(old_last_update, self.rssfeeds["0"]["last_update"]) old_last_update = self.rssfeeds["0"]["last_update"] # Run the subscription with key 0 like when the user runs it manually self.scheduler.rssfeed_update_handler(None, "0") # last_update should not have changed self.assertEquals(old_last_update, self.rssfeeds["0"]["last_update"]) def test_rssfeed_update_handler_exception(self): subscription = yarss2.yarss_config.get_fresh_subscription_config(rssfeed_key="0", key="0") self.config.set_config({"subscriptions": {"0": subscription} }) # Check that last_update changes old_last_update = self.rssfeeds["0"]["last_update"] # Run the rssfeed with invalid key ret = self.scheduler.rssfeed_update_handler_safe("0") self.scheduler.rssfeed_update_handler_safe("0") self.assertFalse(self.scheduler.rssfeed_update_handler_safe(1)) self.assertRaises(KeyError, self.scheduler.rssfeed_update_handler, 1) def test_ttl_value_updated(self): config = common.get_test_config_dict() config["rssfeeds"]["0"]["update_interval"] = 30 config["rssfeeds"]["0"]["obey_ttl"] = True config["rssfeeds"]["0"]["url"] = yarss2.util.common.get_resource(common.testdata_rssfeed_filename, path="tests") yarss_config = common.get_test_config() yarss_config.set_config(config) self.scheduler.disable_timers() self.scheduler.yarss_config = yarss_config self.scheduler.enable_timers() def add_torrents_pass(*arg): pass self.scheduler.add_torrent_func = add_torrents_pass # Run the rssfeed with key 0 self.scheduler.rssfeed_update_handler("0") # Verify that update_interval of rssfeed in config was updated self.assertEquals(yarss_config.get_config()["rssfeeds"]["0"]["update_interval"], 60) # Verify that update_interval of the timer was updated self.assertEquals(self.scheduler.rssfeed_timers["0"]["update_interval"], 60) self.scheduler.disable_timers() def test_rssfeed_update_queue(self): """Tests that the add_torrent_func is called the correct number of times, and that add_torrent_func is running in the main thread. """ # Don't use the loopingcall, so disable just to avoid any trouble self.scheduler.disable_timers() self.config.set_config(common.get_test_config_dict()) add_torrents_count = [] main_thread = threading.current_thread() def add_torrents_cb(*arg): self.assertEquals(main_thread, threading.current_thread(), "add_torrents must be called from the main thread!") add_torrents_count.append(0) self.scheduler.add_torrent_func = add_torrents_cb d_first = self.scheduler.queue_rssfeed_update(rssfeed_key="0") self.scheduler.queue_rssfeed_update(subscription_key="1") self.scheduler.queue_rssfeed_update(rssfeed_key="1") d_last = self.scheduler.queue_rssfeed_update(rssfeed_key="2") def verify_callback_count(args): self.assertEquals(len(add_torrents_count), 3) d_last.addCallback(verify_callback_count) return d_last