class TrackersManagerDbPartTest(DbTestCase):
    DISPLAY_NAME1 = "Some Name / Translated Name"
    URL1 = "http://tracker.com/1/"

    def setUp(self):
        super(TrackersManagerDbPartTest, self).setUp()

        with DBSession() as db:
            topic = Tracker1Topic(display_name=self.DISPLAY_NAME1,
                                  url=self.URL1,
                                  type=TRACKER1_PLUGIN_NAME,
                                  some_addition_field=1)
            db.add(topic)
            db.commit()
            self.tracker1_id1 = topic.id

        self.tracker1 = Tracker1()
        self.tracker2 = Tracker2()

        tracker_settings = TrackerSettings(10, None)
        settings_manager = Mock()
        settings_manager.tracker_settings = tracker_settings

        # noinspection PyTypeChecker
        self.trackers_manager = TrackersManager(
            settings_manager, {
                TRACKER1_PLUGIN_NAME: self.tracker1,
                TRACKER2_PLUGIN_NAME: self.tracker2,
            })

    def create_removed_topic(self):
        remove_type = TRACKER1_PLUGIN_NAME + ".uk"
        with DBSession() as db:
            topic = Topic(display_name=self.DISPLAY_NAME1 + " / Test",
                          url="http://tracker.com/2/",
                          type=remove_type)
            result = db.execute(
                topic.__table__.insert(),
                row2dict(topic, fields=['display_name', 'url', 'type']))
            tracker1_id2 = result.inserted_primary_key[0]
        return tracker1_id2

    def test_remove_topic_1(self):
        self.assertTrue(self.trackers_manager.remove_topic(self.tracker1_id1))
        with DBSession() as db:
            topic = db.query(Topic).filter(
                Topic.id == self.tracker1_id1).first()
            self.assertIsNone(topic)

    def test_remove_topic_2(self):
        with self.assertRaises(KeyError):
            self.trackers_manager.remove_topic(self.tracker1_id1 + 1)
        with DBSession() as db:
            topic = db.query(Topic).filter(
                Topic.id == self.tracker1_id1).first()
            self.assertIsNotNone(topic)

    def test_get_topic_1(self):
        topic_settings = {'display_name': self.DISPLAY_NAME1}
        get_topic_mock = MagicMock(return_value=topic_settings)
        self.tracker1.get_topic = get_topic_mock

        result = self.trackers_manager.get_topic(self.tracker1_id1)

        self.assertEqual(
            {
                'form': self.tracker1.topic_form,
                'settings': topic_settings
            }, result)

        get_topic_mock.assert_called_with(self.tracker1_id1)

    def test_get_topic_2(self):
        with self.assertRaises(KeyError):
            self.trackers_manager.get_topic(self.tracker1_id1 + 1)

    def test_get_topic_3(self):
        tracker1_id2 = self.create_removed_topic()

        with self.assertRaises(KeyError):
            self.trackers_manager.get_topic(tracker1_id2)

    @data(True, False)
    def test_update_topic_1(self, value):
        topic_settings = {'display_name': self.DISPLAY_NAME1}
        update_topic_mock = MagicMock(return_value=value)
        self.tracker1.update_topic = update_topic_mock

        self.assertEqual(
            value,
            self.trackers_manager.update_topic(self.tracker1_id1,
                                               topic_settings))

        update_topic_mock.assert_called_with(self.tracker1_id1, topic_settings)

    def test_update_topic_2(self):
        tracker1_id2 = self.create_removed_topic()

        with self.assertRaises(KeyError):
            self.trackers_manager.get_topic(tracker1_id2)

    def test_reset_topic_status_1(self):
        with DBSession() as db:
            topic = db.query(Topic).filter(
                Topic.id == self.tracker1_id1).first()
            topic.status = Status.NotFound
        topic = self.trackers_manager.get_watching_topics()[0]
        self.assertEqual(topic['status'], str(Status.NotFound))

        self.trackers_manager.reset_topic_status(self.tracker1_id1)
        topic = self.trackers_manager.get_watching_topics()[0]
        self.assertEqual(topic['status'], str(Status.Ok))

    def test_reset_topic_status_2(self):
        tracker1_id2 = self.tracker1_id1 * 100

        with self.assertRaises(KeyError):
            self.trackers_manager.reset_topic_status(tracker1_id2)

    def test_set_topic_paused_success(self):
        with DBSession() as db:
            topic = db.query(Topic).filter(
                Topic.id == self.tracker1_id1).first()
            topic.paused = True
        topic = self.trackers_manager.get_watching_topics()[0]
        self.assertEqual(topic['paused'], True)

        self.trackers_manager.set_topic_paused(self.tracker1_id1, False)
        topic = self.trackers_manager.get_watching_topics()[0]
        self.assertEqual(topic['paused'], False)

        self.trackers_manager.set_topic_paused(self.tracker1_id1, True)
        topic = self.trackers_manager.get_watching_topics()[0]
        self.assertEqual(topic['paused'], True)

    def test_reset_topic_status_failed(self):
        tracker1_id2 = self.tracker1_id1 * 100

        with self.assertRaises(KeyError):
            self.trackers_manager.set_topic_paused(tracker1_id2, True)

    def test_get_watching_topics_1(self):
        topics = self.trackers_manager.get_watching_topics()

        self.assertIsNotNone(topics)
        self.assertEqual(1, len(topics))
        self.assertEqual([{
            'id': self.tracker1_id1,
            'display_name': self.DISPLAY_NAME1,
            'url': self.URL1,
            'last_update': None,
            'info': None,
            'tracker': TRACKER1_PLUGIN_NAME,
            'status': Status.Ok.__str__(),
            'paused': False
        }], topics)

    def test_get_watching_topics_2(self):
        with DBSession() as db:
            topic2 = Tracker2Topic(display_name='Some Name 2 / Other Name 2',
                                   url='https://tracker2.tracker/2',
                                   type=TRACKER2_PLUGIN_NAME,
                                   some_addition_field=2,
                                   status=Status.Ok)
            db.add(topic2)
            db.commit()

            topic2_id = topic2.id

        topics = self.trackers_manager.get_watching_topics()

        self.assertIsNotNone(topics)
        self.assertEqual(2, len(topics))
        self.assertEqual([{
            'id': self.tracker1_id1,
            'display_name': self.DISPLAY_NAME1,
            'url': self.URL1,
            'last_update': None,
            'info': None,
            'tracker': TRACKER1_PLUGIN_NAME,
            'status': Status.Ok.__str__(),
            'paused': False
        }, {
            'id': topic2_id,
            'display_name': 'Some Name 2 / Other Name 2',
            'url': 'https://tracker2.tracker/2',
            'last_update': None,
            'info': None,
            'tracker': TRACKER2_PLUGIN_NAME,
            'thumbnail_url': 'https://tracker2.tracker/2/poster.jpg',
            'status': Status.Ok.__str__(),
            'paused': False
        }], topics)

    def test_get_watching_topics_3(self):
        self.create_removed_topic()

        topics = self.trackers_manager.get_watching_topics()

        self.assertIsNotNone(topics)
        self.assertEqual(1, len(topics))
        self.assertEqual([{
            'id': self.tracker1_id1,
            'display_name': self.DISPLAY_NAME1,
            'url': self.URL1,
            'last_update': None,
            'info': None,
            'tracker': TRACKER1_PLUGIN_NAME,
            'status': Status.Ok.__str__(),
            'paused': False
        }], topics)

    def test_get_tracker_topics(self):
        topics = self.trackers_manager.get_tracker_topics(TRACKER1_PLUGIN_NAME)

        self.assertIsNotNone(topics)
        self.assertEqual(len(topics), 1)
        self.assertEqual(topics[0].id, self.tracker1_id1)

        topics = self.trackers_manager.get_tracker_topics(TRACKER2_PLUGIN_NAME)

        self.assertEqual(topics, [])

    def test_get_tracker_topics_key_error(self):
        topics = self.trackers_manager.get_tracker_topics(TRACKER1_PLUGIN_NAME)

        self.assertIsNotNone(topics)
        self.assertEqual(len(topics), 1)
        self.assertEqual(topics[0].id, self.tracker1_id1)

        with self.assertRaises(KeyError):
            self.trackers_manager.get_tracker_topics('UnknowTracker')

    def test_get_status_topics(self):
        with DBSession() as db:
            topic1 = Tracker1Topic(display_name=self.DISPLAY_NAME1 + '/1',
                                   url=self.URL1 + '/1',
                                   type=TRACKER1_PLUGIN_NAME,
                                   some_addition_field=1,
                                   status=Status.Error)
            db.add(topic1)
            topic2 = Tracker1Topic(display_name=self.DISPLAY_NAME1 + '/2',
                                   url=self.URL1 + '/2',
                                   type=TRACKER1_PLUGIN_NAME,
                                   some_addition_field=1,
                                   status=Status.NotFound)
            db.add(topic2)
            topic3 = Tracker2Topic(display_name=self.DISPLAY_NAME1 + '/3',
                                   url=self.URL1 + '/3',
                                   type=TRACKER2_PLUGIN_NAME,
                                   some_addition_field=1,
                                   status=Status.Unknown)
            db.add(topic3)
            db.commit()

            topic1_id = topic1.id
            topic2_id = topic2.id
            topic3_id = topic3.id

        topics = self.trackers_manager.get_status_topics_ids([Status.Ok])

        self.assertEqual(len(topics), 1)
        self.assertEqual(topics[0], self.tracker1_id1)

        topics = self.trackers_manager.get_status_topics_ids([Status.Error])

        self.assertEqual(len(topics), 1)
        self.assertEqual(topics[0], topic1_id)

        topics = self.trackers_manager.get_status_topics_ids([Status.NotFound])

        self.assertEqual(len(topics), 1)
        self.assertEqual(topics[0], topic2_id)

        topics = self.trackers_manager.get_status_topics_ids([Status.Unknown])

        self.assertEqual(len(topics), 1)
        self.assertEqual(topics[0], topic3_id)

        topics = self.trackers_manager.get_status_topics_ids(
            [Status.Error, Status.NotFound])

        self.assertEqual(len(topics), 2)
        self.assertListEqual(sorted(topics), sorted([topic1_id, topic2_id]))
class TrackersManagerDbPartTest(DbTestCase):
    DISPLAY_NAME1 = "Some Name / Translated Name"
    URL1 = "http://tracker.com/1/"

    def setUp(self):
        super(TrackersManagerDbPartTest, self).setUp()

        with DBSession() as db:
            topic = Tracker1Topic(display_name=self.DISPLAY_NAME1,
                                  url=self.URL1,
                                  type=TRACKER1_PLUGIN_NAME,
                                  some_addition_field=1)
            db.add(topic)
            db.commit()
            self.tracker1_id1 = topic.id

        self.tracker1 = Tracker1()
        self.tracker2 = Tracker2()
        self.trackers_manager = TrackersManager(
            TrackerSettings(10), {
                TRACKER1_PLUGIN_NAME: self.tracker1,
                TRACKER2_PLUGIN_NAME: self.tracker2,
            })

    def create_removed_topic(self):
        remove_type = TRACKER1_PLUGIN_NAME + ".uk"
        with DBSession() as db:
            topic = Topic(display_name=self.DISPLAY_NAME1 + " / Test",
                          url="http://tracker.com/2/",
                          type=remove_type)
            result = db.execute(
                topic.__table__.insert(),
                row2dict(topic, fields=['display_name', 'url', 'type']))
            tracker1_id2 = result.inserted_primary_key[0]
        return tracker1_id2

    def test_remove_topic_1(self):
        self.assertTrue(self.trackers_manager.remove_topic(self.tracker1_id1))
        with DBSession() as db:
            topic = db.query(Topic).filter(
                Topic.id == self.tracker1_id1).first()
            self.assertIsNone(topic)

    def test_remove_topic_2(self):
        with self.assertRaises(KeyError):
            self.trackers_manager.remove_topic(self.tracker1_id1 + 1)
        with DBSession() as db:
            topic = db.query(Topic).filter(
                Topic.id == self.tracker1_id1).first()
            self.assertIsNotNone(topic)

    def test_get_topic_1(self):
        topic_settings = {'display_name': self.DISPLAY_NAME1}
        get_topic_mock = MagicMock(return_value=topic_settings)
        self.tracker1.get_topic = get_topic_mock

        result = self.trackers_manager.get_topic(self.tracker1_id1)

        self.assertEqual(
            {
                'form': self.tracker1.topic_form,
                'settings': topic_settings
            }, result)

        get_topic_mock.assert_called_with(self.tracker1_id1)

    def test_get_topic_2(self):
        with self.assertRaises(KeyError):
            self.trackers_manager.get_topic(self.tracker1_id1 + 1)

    def test_get_topic_3(self):
        tracker1_id2 = self.create_removed_topic()

        with self.assertRaises(KeyError):
            self.trackers_manager.get_topic(tracker1_id2)

    @data(True, False)
    def test_update_topic_1(self, value):
        topic_settings = {'display_name': self.DISPLAY_NAME1}
        update_topic_mock = MagicMock(return_value=value)
        self.tracker1.update_topic = update_topic_mock

        self.assertEqual(
            value,
            self.trackers_manager.update_topic(self.tracker1_id1,
                                               topic_settings))

        update_topic_mock.assert_called_with(self.tracker1_id1, topic_settings)

    def test_update_topic_2(self):
        tracker1_id2 = self.create_removed_topic()

        with self.assertRaises(KeyError):
            self.trackers_manager.get_topic(tracker1_id2)

    def test_reset_topic_status_1(self):
        with DBSession() as db:
            topic = db.query(Topic).filter(
                Topic.id == self.tracker1_id1).first()
            topic.status = Status.NotFound
        topic = self.trackers_manager.get_watching_topics()[0]
        self.assertEqual(topic['status'], str(Status.NotFound))

        self.trackers_manager.reset_topic_status(self.tracker1_id1)
        topic = self.trackers_manager.get_watching_topics()[0]
        self.assertEqual(topic['status'], str(Status.Ok))

    def test_reset_topic_status_2(self):
        tracker1_id2 = self.tracker1_id1 * 100

        with self.assertRaises(KeyError):
            self.trackers_manager.reset_topic_status(tracker1_id2)

    def test_get_watching_topics_1(self):
        topics = self.trackers_manager.get_watching_topics()

        self.assertIsNotNone(topics)
        self.assertEqual(1, len(topics))
        self.assertEqual([{
            'id': self.tracker1_id1,
            'display_name': self.DISPLAY_NAME1,
            'url': self.URL1,
            'last_update': None,
            'info': None,
            'tracker': TRACKER1_PLUGIN_NAME,
            'status': Status.Ok.__str__()
        }], topics)

    def test_get_watching_topics_2(self):
        self.create_removed_topic()

        topics = self.trackers_manager.get_watching_topics()

        self.assertIsNotNone(topics)
        self.assertEqual(1, len(topics))
        self.assertEqual([{
            'id': self.tracker1_id1,
            'display_name': self.DISPLAY_NAME1,
            'url': self.URL1,
            'last_update': None,
            'info': None,
            'tracker': TRACKER1_PLUGIN_NAME,
            'status': Status.Ok.__str__()
        }], topics)

    def test_get_tracker_topics(self):
        topics = self.trackers_manager.get_tracker_topics(TRACKER1_PLUGIN_NAME)

        self.assertIsNotNone(topics)
        self.assertEqual(len(topics), 1)
        self.assertEqual(topics[0].id, self.tracker1_id1)

        topics = self.trackers_manager.get_tracker_topics(TRACKER2_PLUGIN_NAME)

        self.assertEqual(topics, [])

    def test_get_tracker_topics_key_error(self):
        topics = self.trackers_manager.get_tracker_topics(TRACKER1_PLUGIN_NAME)

        self.assertIsNotNone(topics)
        self.assertEqual(len(topics), 1)
        self.assertEqual(topics[0].id, self.tracker1_id1)

        with self.assertRaises(KeyError):
            self.trackers_manager.get_tracker_topics('UnknowTracker')

    def test_get_status_topics(self):
        with DBSession() as db:
            topic1 = Tracker1Topic(display_name=self.DISPLAY_NAME1 + '/1',
                                   url=self.URL1 + '/1',
                                   type=TRACKER1_PLUGIN_NAME,
                                   some_addition_field=1,
                                   status=Status.Error)
            db.add(topic1)
            topic2 = Tracker1Topic(display_name=self.DISPLAY_NAME1 + '/2',
                                   url=self.URL1 + '/2',
                                   type=TRACKER1_PLUGIN_NAME,
                                   some_addition_field=1,
                                   status=Status.NotFound)
            db.add(topic2)
            topic3 = Tracker2Topic(display_name=self.DISPLAY_NAME1 + '/3',
                                   url=self.URL1 + '/3',
                                   type=TRACKER2_PLUGIN_NAME,
                                   some_addition_field=1,
                                   status=Status.Unknown)
            db.add(topic3)
            db.commit()

            topic1_id = topic1.id
            topic2_id = topic2.id
            topic3_id = topic3.id

        topics = self.trackers_manager.get_status_topics_ids([Status.Ok])

        self.assertEqual(len(topics), 1)
        self.assertEqual(topics[0], self.tracker1_id1)

        topics = self.trackers_manager.get_status_topics_ids([Status.Error])

        self.assertEqual(len(topics), 1)
        self.assertEqual(topics[0], topic1_id)

        topics = self.trackers_manager.get_status_topics_ids([Status.NotFound])

        self.assertEqual(len(topics), 1)
        self.assertEqual(topics[0], topic2_id)

        topics = self.trackers_manager.get_status_topics_ids([Status.Unknown])

        self.assertEqual(len(topics), 1)
        self.assertEqual(topics[0], topic3_id)

        topics = self.trackers_manager.get_status_topics_ids(
            [Status.Error, Status.NotFound])

        self.assertEqual(len(topics), 2)
        self.assertListEqual(sorted(topics), sorted([topic1_id, topic2_id]))

    def test_execute_success(self):
        engine = Mock()
        engine.log = Mock()
        engine.log.info = MagicMock()
        engine.log.failed = MagicMock()

        execute_mock = MagicMock()

        topics = [Mock()]
        get_topics_mock = Mock(return_value=topics)

        self.tracker1.execute = execute_mock
        self.tracker1.get_topics = get_topics_mock

        self.tracker2.execute = execute_mock
        self.tracker2.get_topics = get_topics_mock

        self.trackers_manager.execute(engine, None)

        self.assertTrue(engine.log.info.called)
        self.assertFalse(engine.log.failed.called)
        get_topics_mock.assert_called_with(None)
        execute_mock.assert_called_with(topics, engine)

    def test_execute_fails(self):
        engine = Mock()
        engine.log = Mock()
        engine.log.info = MagicMock()
        engine.log.failed = MagicMock()

        topics = [Mock()]
        get_topics_mock = Mock(return_value=topics)

        execute_mock1 = MagicMock(side_effect=Exception)
        execute_mock2 = MagicMock(side_effect=Exception)

        self.tracker1.execute = execute_mock1
        self.tracker1.get_topics = get_topics_mock

        self.tracker2.execute = execute_mock2
        self.tracker2.get_topics = get_topics_mock

        self.trackers_manager.execute(engine, None)

        self.assertTrue(engine.log.info.called)
        self.assertTrue(engine.log.failed.called)
        get_topics_mock.assert_called_with(None)
        execute_mock1.assert_called_with(topics, engine)
        execute_mock2.assert_called_with(topics, engine)

    def test_execute_skip_one_plugin(self):
        engine = Mock()
        engine.log = Mock()
        engine.log.info = MagicMock()
        engine.log.failed = MagicMock()

        topics1 = [Mock()]
        get_topics_mock1 = Mock(return_value=topics1)

        topics2 = []
        get_topics_mock2 = Mock(return_value=topics2)

        execute_mock1 = Mock()
        # Exception shouldn't be thrown because there are no tocpis for plugin
        execute_mock2 = Mock(return_value=Exception)

        self.tracker1.execute = execute_mock1
        self.tracker1.get_topics = get_topics_mock1

        self.tracker2.execute = execute_mock2
        self.tracker2.get_topics = get_topics_mock2

        self.trackers_manager.execute(engine, None)

        self.assertTrue(engine.log.info.called)
        self.assertFalse(engine.log.failed.called
                         )  # Check that exception from tracker2 wasn't raised
        get_topics_mock1.assert_called_with(None)
        execute_mock1.assert_called_with(topics1, engine)
        get_topics_mock2.assert_called_with(None)
        execute_mock2.assert_not_called()

    def test_execute_with_ids(self):
        engine = Mock()
        engine.log = Mock()
        engine.log.info = MagicMock()
        engine.log.failed = MagicMock()

        topics1 = [Mock()]
        get_topics_mock1 = Mock(return_value=topics1)

        topics2 = []
        get_topics_mock2 = Mock(return_value=topics2)

        execute_mock1 = Mock()
        # Exception shouldn't be thrown because there are no tocpis for plugin
        execute_mock2 = Mock(return_value=Exception)

        self.tracker1.execute = execute_mock1
        self.tracker1.get_topics = get_topics_mock1

        self.tracker2.execute = execute_mock2
        self.tracker2.get_topics = get_topics_mock2

        ids = [1, 2]
        self.trackers_manager.execute(engine, ids)

        self.assertTrue(engine.log.info.called)
        self.assertFalse(engine.log.failed.called
                         )  # Check that exception from tracker2 wasn't raised
        get_topics_mock1.assert_called_with(ids)
        execute_mock1.assert_called_with(topics1, engine)
        get_topics_mock2.assert_called_with(ids)
        execute_mock2.assert_not_called()
class TrackersManagerDbPartTest(DbTestCase):
    DISPLAY_NAME1 = "Some Name / Translated Name"
    URL1 = "http://tracker.com/1/"

    def setUp(self):
        super(TrackersManagerDbPartTest, self).setUp()

        with DBSession() as db:
            topic = Tracker1Topic(display_name=self.DISPLAY_NAME1,
                                  url=self.URL1,
                                  type=TRACKER1_PLUGIN_NAME,
                                  some_addition_field=1)
            db.add(topic)
            db.commit()
            self.tracker1_id1 = topic.id

        self.tracker1 = Tracker1()
        self.tracker2 = Tracker2()

        tracker_settings = TrackerSettings(10, None)
        settings_manager = Mock()
        settings_manager.tracker_settings = tracker_settings

        # noinspection PyTypeChecker
        self.trackers_manager = TrackersManager(settings_manager, {
            TRACKER1_PLUGIN_NAME: self.tracker1,
            TRACKER2_PLUGIN_NAME: self.tracker2,
        })

    def create_removed_topic(self):
        remove_type = TRACKER1_PLUGIN_NAME + ".uk"
        with DBSession() as db:
            topic = Topic(display_name=self.DISPLAY_NAME1 + " / Test",
                          url="http://tracker.com/2/",
                          type=remove_type)
            result = db.execute(topic.__table__.insert(), row2dict(topic, fields=['display_name', 'url', 'type']))
            tracker1_id2 = result.inserted_primary_key[0]
        return tracker1_id2

    def test_remove_topic_1(self):
        self.assertTrue(self.trackers_manager.remove_topic(self.tracker1_id1))
        with DBSession() as db:
            topic = db.query(Topic).filter(Topic.id == self.tracker1_id1).first()
            self.assertIsNone(topic)

    def test_remove_topic_2(self):
        with self.assertRaises(KeyError):
            self.trackers_manager.remove_topic(self.tracker1_id1 + 1)
        with DBSession() as db:
            topic = db.query(Topic).filter(Topic.id == self.tracker1_id1).first()
            self.assertIsNotNone(topic)

    def test_get_topic_1(self):
        topic_settings = {'display_name': self.DISPLAY_NAME1}
        get_topic_mock = MagicMock(return_value=topic_settings)
        self.tracker1.get_topic = get_topic_mock

        result = self.trackers_manager.get_topic(self.tracker1_id1)

        self.assertEqual({'form': self.tracker1.topic_form, 'settings': topic_settings}, result)

        get_topic_mock.assert_called_with(self.tracker1_id1)

    def test_get_topic_2(self):
        with self.assertRaises(KeyError):
            self.trackers_manager.get_topic(self.tracker1_id1 + 1)

    def test_get_topic_3(self):
        tracker1_id2 = self.create_removed_topic()

        with self.assertRaises(KeyError):
            self.trackers_manager.get_topic(tracker1_id2)

    @data(True, False)
    def test_update_topic_1(self, value):
        topic_settings = {'display_name': self.DISPLAY_NAME1}
        update_topic_mock = MagicMock(return_value=value)
        self.tracker1.update_topic = update_topic_mock

        self.assertEqual(value, self.trackers_manager.update_topic(self.tracker1_id1, topic_settings))

        update_topic_mock.assert_called_with(self.tracker1_id1, topic_settings)

    def test_update_topic_2(self):
        tracker1_id2 = self.create_removed_topic()

        with self.assertRaises(KeyError):
            self.trackers_manager.get_topic(tracker1_id2)

    def test_reset_topic_status_1(self):
        with DBSession() as db:
            topic = db.query(Topic).filter(Topic.id == self.tracker1_id1).first()
            topic.status = Status.NotFound
        topic = self.trackers_manager.get_watching_topics()[0]
        self.assertEqual(topic['status'], str(Status.NotFound))

        self.trackers_manager.reset_topic_status(self.tracker1_id1)
        topic = self.trackers_manager.get_watching_topics()[0]
        self.assertEqual(topic['status'], str(Status.Ok))

    def test_reset_topic_status_2(self):
        tracker1_id2 = self.tracker1_id1 * 100

        with self.assertRaises(KeyError):
            self.trackers_manager.reset_topic_status(tracker1_id2)

    def test_set_topic_paused_success(self):
        with DBSession() as db:
            topic = db.query(Topic).filter(Topic.id == self.tracker1_id1).first()
            topic.paused = True
        topic = self.trackers_manager.get_watching_topics()[0]
        self.assertEqual(topic['paused'], True)

        self.trackers_manager.set_topic_paused(self.tracker1_id1, False)
        topic = self.trackers_manager.get_watching_topics()[0]
        self.assertEqual(topic['paused'], False)

        self.trackers_manager.set_topic_paused(self.tracker1_id1, True)
        topic = self.trackers_manager.get_watching_topics()[0]
        self.assertEqual(topic['paused'], True)

    def test_reset_topic_status_failed(self):
        tracker1_id2 = self.tracker1_id1 * 100

        with self.assertRaises(KeyError):
            self.trackers_manager.set_topic_paused(tracker1_id2, True)

    def test_get_watching_topics_1(self):
        topics = self.trackers_manager.get_watching_topics()

        self.assertIsNotNone(topics)
        self.assertEqual(1, len(topics))
        self.assertEqual([
            {
                'id': self.tracker1_id1,
                'display_name': self.DISPLAY_NAME1,
                'url': self.URL1,
                'last_update': None,
                'info': None,
                'tracker': TRACKER1_PLUGIN_NAME,
                'status': Status.Ok.__str__(),
                'paused': False
            }],
            topics)

    def test_get_watching_topics_2(self):
        self.create_removed_topic()

        topics = self.trackers_manager.get_watching_topics()

        self.assertIsNotNone(topics)
        self.assertEqual(1, len(topics))
        self.assertEqual([
            {
                'id': self.tracker1_id1,
                'display_name': self.DISPLAY_NAME1,
                'url': self.URL1,
                'last_update': None,
                'info': None,
                'tracker': TRACKER1_PLUGIN_NAME,
                'status': Status.Ok.__str__(),
                'paused': False
            }],
            topics)

    def test_get_tracker_topics(self):
        topics = self.trackers_manager.get_tracker_topics(TRACKER1_PLUGIN_NAME)

        self.assertIsNotNone(topics)
        self.assertEqual(len(topics), 1)
        self.assertEqual(topics[0].id, self.tracker1_id1)

        topics = self.trackers_manager.get_tracker_topics(TRACKER2_PLUGIN_NAME)

        self.assertEqual(topics, [])

    def test_get_tracker_topics_key_error(self):
        topics = self.trackers_manager.get_tracker_topics(TRACKER1_PLUGIN_NAME)

        self.assertIsNotNone(topics)
        self.assertEqual(len(topics), 1)
        self.assertEqual(topics[0].id, self.tracker1_id1)

        with self.assertRaises(KeyError):
            self.trackers_manager.get_tracker_topics('UnknowTracker')

    def test_get_status_topics(self):
        with DBSession() as db:
            topic1 = Tracker1Topic(display_name=self.DISPLAY_NAME1 + '/1',
                                   url=self.URL1 + '/1',
                                   type=TRACKER1_PLUGIN_NAME,
                                   some_addition_field=1,
                                   status=Status.Error)
            db.add(topic1)
            topic2 = Tracker1Topic(display_name=self.DISPLAY_NAME1 + '/2',
                                   url=self.URL1 + '/2',
                                   type=TRACKER1_PLUGIN_NAME,
                                   some_addition_field=1,
                                   status=Status.NotFound)
            db.add(topic2)
            topic3 = Tracker2Topic(display_name=self.DISPLAY_NAME1 + '/3',
                                   url=self.URL1 + '/3',
                                   type=TRACKER2_PLUGIN_NAME,
                                   some_addition_field=1,
                                   status=Status.Unknown)
            db.add(topic3)
            db.commit()

            topic1_id = topic1.id
            topic2_id = topic2.id
            topic3_id = topic3.id

        topics = self.trackers_manager.get_status_topics_ids([Status.Ok])

        self.assertEqual(len(topics), 1)
        self.assertEqual(topics[0], self.tracker1_id1)

        topics = self.trackers_manager.get_status_topics_ids([Status.Error])

        self.assertEqual(len(topics), 1)
        self.assertEqual(topics[0], topic1_id)

        topics = self.trackers_manager.get_status_topics_ids([Status.NotFound])

        self.assertEqual(len(topics), 1)
        self.assertEqual(topics[0], topic2_id)

        topics = self.trackers_manager.get_status_topics_ids([Status.Unknown])

        self.assertEqual(len(topics), 1)
        self.assertEqual(topics[0], topic3_id)

        topics = self.trackers_manager.get_status_topics_ids([Status.Error, Status.NotFound])

        self.assertEqual(len(topics), 2)
        self.assertListEqual(sorted(topics), sorted([topic1_id, topic2_id]))

    def test_execute_success(self):
        engine = Mock()
        engine.log = Mock()
        engine.log.info = MagicMock()
        engine.log.failed = MagicMock()

        execute_mock = MagicMock()

        topics = [Mock()]
        get_topics_mock = Mock(return_value=topics)

        self.tracker1.execute = execute_mock
        self.tracker1.get_topics = get_topics_mock

        self.tracker2.execute = execute_mock
        self.tracker2.get_topics = get_topics_mock

        self.trackers_manager.execute(engine, None)

        self.assertTrue(engine.log.info.called)
        self.assertFalse(engine.log.failed.called)
        get_topics_mock.assert_called_with(None)
        execute_mock.assert_called_with(topics, engine)

    def test_execute_fails(self):
        engine = Mock()
        engine.log = Mock()
        engine.log.info = MagicMock()
        engine.log.failed = MagicMock()

        topics = [Mock()]
        get_topics_mock = Mock(return_value=topics)

        execute_mock1 = MagicMock(side_effect=Exception)
        execute_mock2 = MagicMock(side_effect=Exception)

        self.tracker1.execute = execute_mock1
        self.tracker1.get_topics = get_topics_mock

        self.tracker2.execute = execute_mock2
        self.tracker2.get_topics = get_topics_mock

        self.trackers_manager.execute(engine, None)

        self.assertTrue(engine.log.info.called)
        self.assertTrue(engine.log.failed.called)
        get_topics_mock.assert_called_with(None)
        execute_mock1.assert_called_with(topics, engine)
        execute_mock2.assert_called_with(topics, engine)

    def test_execute_skip_one_plugin(self):
        engine = Mock()
        engine.log = Mock()
        engine.log.info = MagicMock()
        engine.log.failed = MagicMock()

        topics1 = [Mock()]
        get_topics_mock1 = Mock(return_value=topics1)

        topics2 = []
        get_topics_mock2 = Mock(return_value=topics2)

        execute_mock1 = Mock()
        # Exception shouldn't be thrown because there are no tocpis for plugin
        execute_mock2 = Mock(return_value=Exception)

        self.tracker1.execute = execute_mock1
        self.tracker1.get_topics = get_topics_mock1

        self.tracker2.execute = execute_mock2
        self.tracker2.get_topics = get_topics_mock2

        self.trackers_manager.execute(engine, None)

        self.assertTrue(engine.log.info.called)
        self.assertFalse(engine.log.failed.called)  # Check that exception from tracker2 wasn't raised
        get_topics_mock1.assert_called_with(None)
        execute_mock1.assert_called_with(topics1, engine)
        get_topics_mock2.assert_called_with(None)
        execute_mock2.assert_not_called()

    def test_execute_with_ids(self):
        engine = Mock()
        engine.log = Mock()
        engine.log.info = MagicMock()
        engine.log.failed = MagicMock()

        topics1 = [Mock()]
        get_topics_mock1 = Mock(return_value=topics1)

        topics2 = []
        get_topics_mock2 = Mock(return_value=topics2)

        execute_mock1 = Mock()
        # Exception shouldn't be thrown because there are no tocpis for plugin
        execute_mock2 = Mock(return_value=Exception)

        self.tracker1.execute = execute_mock1
        self.tracker1.get_topics = get_topics_mock1

        self.tracker2.execute = execute_mock2
        self.tracker2.get_topics = get_topics_mock2

        ids = [1, 2]
        self.trackers_manager.execute(engine, ids)

        self.assertTrue(engine.log.info.called)
        self.assertFalse(engine.log.failed.called)  # Check that exception from tracker2 wasn't raised
        get_topics_mock1.assert_called_with(ids)
        execute_mock1.assert_called_with(topics1, engine)
        get_topics_mock2.assert_called_with(ids)
        execute_mock2.assert_not_called()