예제 #1
0
파일: cli.py 프로젝트: wpappdev/Yatcobot
def main():
    parser = argparse.ArgumentParser(description='Yatcobot: a bot for entering twitter contests')
    parser.add_argument('--config', '-c', dest='config', default='config.yaml', help='Path of the config file')
    parser.add_argument('--ignore_list', '-i', dest='ignore_list', default='ignorelist', help='Path of the ignore file')
    parser.add_argument('--log', dest='logfile', default=None, help='Path of log file')
    parser.add_argument('--test-mail', action='store_true', dest='test_mail', default=False, help='Test mail settings')
    parser.add_argument('--debug', dest='debug', action='store_true', help='Enable debug')

    args = parser.parse_args()

    # Create logger
    if args.debug:
        create_logger(logging.DEBUG, args.logfile)
    else:
        create_logger(logging.INFO, args.logfile)

    # Check for old config
    if args.config.endswith('.json') or (os.path.isfile('config.json') and not os.path.isfile('config.yaml')):
        logger.error("Config file format changed, please update your config to the new yaml format!")
        logger.error("Visit documentation for more info: https://yatcobot.readthedocs.io/en/master/config.html")
        exit(1)

    logger.info("Loading configuration")
    TwitterConfig.load(args.config)
    logger.info("Configuration loaded")

    # Test mail settings and exit
    if args.test_mail:
        MailNotifier.from_config().test()
        exit(1)

    logger.info("Starting")
    print_logo()
    bot = Yatcobot(args.ignore_list)
    bot.run()
예제 #2
0
파일: cli.py 프로젝트: buluba89/Yatcobot
def main():
    parser = argparse.ArgumentParser(description="Yatcobot: a bot for entering twitter contests")
    parser.add_argument("--login", dest="login", action="store_true", help="Login to twitter to get tokens")
    parser.add_argument("--config", "-c", dest="config", default="config.json", help="Path of the config file")
    parser.add_argument("--ignore_list", "-i", dest="ignore_list", default="ignorelist", help="Path of the ignore file")
    parser.add_argument("--log", dest="logfile", default=None, help="Path of log file")
    parser.add_argument("--debug", dest="debug", action="store_true", help="Enable debug")

    args = parser.parse_args()

    # Gets user tokens from twitter and saves them
    if args.login:
        tokens = get_access_token(Config.consumer_key, Config.consumer_secret)

        while True:
            user_input = input("Save tokens to {}? y/n ".format(args.config))
            user_input = user_input.lower()
            if user_input in ["y", "n"]:
                break
            else:
                print("That is not a valid option!")

        if user_input == "y":
            Config.save_user_tokens(args.config, tokens["token"], tokens["secret"])

    # Create logger
    if args.debug:
        create_logger(logging.DEBUG, args.logfile)
    else:
        create_logger(logging.INFO, args.logfile)

    Config.load(args.config)

    bot = Yatcobot(args.ignore_list)
    bot.run()
예제 #3
0
파일: cli.py 프로젝트: AkilesX/Yatcobot
def main():
    parser = argparse.ArgumentParser(description='Yatcobot: a bot for entering twitter contests')
    parser.add_argument('--login', dest='login', action='store_true', help='Login to twitter to get tokens')
    parser.add_argument('--config', '-c', dest='config', default='config.json', help='Path of the config file')
    parser.add_argument('--ignore_list', '-i', dest='ignore_list', default='ignorelist', help='Path of the ignore file')
    parser.add_argument('--log', dest='logfile', default=None, help='Path of log file')
    parser.add_argument('--debug', dest='debug', action='store_true', help='Enable debug')

    args = parser.parse_args()

    #Gets user tokens from twitter and saves them
    if args.login:
        tokens = get_access_token(Config.consumer_key, Config.consumer_secret)

        while True:
            user_input = input('Save tokens to {}? y/n '.format(args.config))
            user_input = user_input.lower()
            if user_input in ['y', 'n']:
                break
            else:
                print('That is not a valid option!')

        if user_input == 'y':
            Config.save_user_tokens(args.config, tokens['token'], tokens['secret'])

    #Create logger
    if args.debug:
        create_logger(logging.DEBUG, args.logfile)
    else:
        create_logger(logging.INFO, args.logfile)


    Config.load(args.config)

    bot = Yatcobot(args.ignore_list)
    bot.run()
예제 #4
0
파일: cli.py 프로젝트: bruvv/Yatcobot
    # Test mail settings and exit
    if args.test_mail:
        if notifier := [
                x for x in NotifierABC.get_enabled()
                if isinstance(x, MailNotifier)
        ]:
            notifier[0].test()
        else:
            logger.error(
                'Mail is not enabled, please enable it in the config and try again'
            )
        exit(1)

    logger.info(f"Starting Yatcobot ({__version__})")
    print_logo()
    bot = Yatcobot(args.ignore_list)
    bot.run()


def print_logo():
    # Figlet font: Standard
    logger.info('''                                                        
                                  .:clcllcll;.                                  
                                ;xc.        .ld'                                
                              .k:     .'..     xd                               
                              x;    cdcc:cx,    xc                              
                             .WolllxO 0oko.XolllxO                              
                              X,...;0.llo,,O....lO                              
                             l0x    .lllclc     0O;                             
                            OOkOk'            :OOdXl                            
                         .dkK;K' col,.    .;ld, oO:Xdo                          
예제 #5
0
 def setUp(self, config_mock, ignore_list_mock, client_mock):
     load_fixture_config()
     self.config = config_mock
     self.client = client_mock
     self.bot = Yatcobot('test')
예제 #6
0
class TestBot(unittest.TestCase):
    tests_path = path = os.path.dirname(os.path.abspath(__file__))

    @patch('yatcobot.bot.TwitterClient')
    @patch('yatcobot.bot.IgnoreList')
    @patch('yatcobot.bot.TwitterConfig')
    def setUp(self, config_mock, ignore_list_mock, client_mock):
        load_fixture_config()
        self.config = config_mock
        self.client = client_mock
        self.bot = Yatcobot('test')

    def test_get_original_tweet_no_retweet(self):
        post = {'id': 1000}
        original = self.bot._get_original_tweet(post)
        self.assertEqual(post, original)

    def test_get_original_tweet_retweet(self):
        post = {'id': 1000, 'retweeted_status': {'id': 1001}}
        original = self.bot._get_original_tweet(post)
        self.assertEqual(post['retweeted_status'], original)

    def test_get_quoted_tweet_similar(self):
        quoted = {'id': 1, 'full_text': 'test'}
        post = {'id': 2, 'full_text': 'test', 'quoted_status': quoted}
        quoted_post_full = {'id': 1, 'full_text': 'test', 'user': {'id:1'}}
        self.bot.client.get_tweet.return_value = quoted_post_full

        r = self.bot._get_quoted_tweet(post)
        self.assertEqual(r, quoted_post_full)

    def test_get_quoted_tweet_quote_of_quotes(self):
        def mock_return(id):
            return mock_return.posts[id]

        mock_return.posts = dict()
        mock_return.posts[1] = {'id': 1, 'full_text': 'test', 'user': {'id:1'}}
        mock_return.posts[2] = {
            'id': 2,
            'full_text': 'test',
            'quoted_status': mock_return.posts[1]
        }
        mock_return.posts[3] = {
            'id': 3,
            'full_text': 'test',
            'quoted_status': mock_return.posts[2]
        }

        self.bot.client.get_tweet.side_effect = mock_return

        r = self.bot._get_quoted_tweet(mock_return.posts[3])
        self.assertEqual(r, mock_return.posts[1])

    def test_get_quoted_tweet_not_similar(self):
        quoted = {'id': 1, 'full_text': 'test'}
        post = {'id': 2, 'full_text': 'test sdfsdfsf', 'quoted_status': quoted}
        quoted_post_full = {'id': 1, 'full_text': 'test', 'user': {'id:1'}}
        self.bot.client.get_tweet.return_value = quoted_post_full

        r = self.bot._get_quoted_tweet(post)
        self.assertEqual(r, post)

    def test_get_quoted_tweet_real_post(self):
        with open(self.tests_path + '/fixtures/post_with_quote.json') as f:
            post = json.load(f)
        quoted_post_full = post.copy()
        quoted_post_full['user'] = {'id': 1}
        self.bot.client.get_tweet.return_value = quoted_post_full

        r = self.bot._get_quoted_tweet(post)
        self.assertEqual(r, quoted_post_full)

    def test_clear_queue_empty(self):
        TwitterConfig.get()['search']['max_queue'] = 60
        self.bot.post_queue = MagicMock()
        self.bot.post_queue.__len__.return_value = 0
        self.bot.clear_queue()
        self.assertFalse(self.bot.post_queue.popitem.called)

    def test_clear_queue_full(self):
        TwitterConfig.get()['search']['max_queue'] = 60
        self.bot.post_queue = MagicMock()
        self.bot.post_queue.__len__.return_value = TwitterConfig.get(
        )['search']['max_queue'] + 1

        self.bot.clear_queue()
        self.assertTrue(self.bot.post_queue.popitem.called)
        self.bot.post_queue.popitem.assert_called_with()

    def test_update_blocked_users(self):
        users = [x for x in range(10)]
        self.bot.ignore_list = list()
        self.bot.client.get_blocks.return_value = users
        self.bot.update_blocked_users()
        self.assertEqual(users, self.bot.ignore_list)

    def test_run(self):
        mock_scheduler = MagicMock(PeriodicScheduler)
        self.bot.scheduler = mock_scheduler
        self.bot.run()
        self.assertEqual(mock_scheduler.enter.call_count, 5)
        self.assertEqual(mock_scheduler.enter_random.call_count, 1)
        self.assertTrue(mock_scheduler.run.called)

    def test_enter_contest_simple_post(self):
        posts = 10
        for i in range(posts):
            self.bot.post_queue[i] = {
                'id': i,
                'full_text': 'test',
                'score': 0,
                'user': {
                    'id': random.randint(1, 1000),
                    'screen_name': 'test'
                },
                'retweeted': False
            }
        queue_copy = self.bot.post_queue.copy()
        self.bot.client.get_tweet = lambda x: queue_copy[x]

        self.bot.enter_contest()

        self.assertEqual(len(self.bot.post_queue), posts - 1)
        self.assertTrue(self.bot.client.retweet.called)
        self.bot.client.retweet.assert_called_with(0)

    def test_enter_contest_already_retweeted_found_from_failed_retweet(self):
        posts = 10
        self.bot.ignore_list = list()
        for i in range(posts):
            self.bot.post_queue[i] = {
                'id': i,
                'full_text': 'test',
                'score': 0,
                'user': {
                    'id': random.randint(1, 1000)
                },
                'retweeted': False
            }
        queue_copy = self.bot.post_queue.copy()
        self.bot.client.retweet.side_effect = TwitterClientRetweetedException()
        self.bot.client.get_tweet = lambda x: queue_copy[x]

        self.bot.enter_contest()

        self.assertEqual(len(self.bot.post_queue), posts - 1)
        self.assertTrue(self.bot.client.retweet.called)
        self.bot.client.retweet.assert_called_with(0)

        self.assertIn(0, self.bot.ignore_list)

    def test_enter_contest_already_retweeted_found_from_getting_post(self):
        posts = 10
        self.bot.ignore_list = list()
        for i in range(posts):
            self.bot.post_queue[i] = {
                'id': i,
                'full_text': 'test',
                'score': 0,
                'user': {
                    'id': random.randint(1, 1000)
                },
                'retweeted': True
            }
        queue_copy = self.bot.post_queue.copy()
        self.bot.client.get_tweet = lambda x: queue_copy[x]

        self.bot.enter_contest()

        self.assertEqual(len(self.bot.post_queue), posts - 1)
        self.assertFalse(self.bot.client.retweet.called)

        self.assertIn(0, self.bot.ignore_list)

    def test_enter_contest_skip_already_retweeted(self):
        TwitterConfig.get()['search']['skip_retweeted'] = True
        posts = 10
        self.bot.ignore_list = list()
        for i in range(posts):
            self.bot.post_queue[i] = {
                'id': i,
                'full_text': 'test',
                'score': 0,
                'user': {
                    'id': random.randint(1, 1000)
                },
                'retweeted': True
            }
        self.bot.post_queue[9]['retweeted'] = False
        queue_copy = self.bot.post_queue.copy()
        self.bot.client.get_tweet = lambda x: queue_copy[x]

        self.bot.enter_contest()

        self.assertEqual(len(self.bot.post_queue), 0)
        self.assertTrue(self.bot.client.retweet.called)
        self.bot.client.retweet.assert_called_with(9)

        self.assertListEqual([x for x in range(10)], self.bot.ignore_list)

    def test_enter_contest_skip_already_retweeted_all_retweeted(self):
        TwitterConfig.get()['search']['skip_retweeted'] = True
        posts = 10
        self.bot.ignore_list = list()
        for i in range(posts):
            self.bot.post_queue[i] = {
                'id': i,
                'full_text': 'test',
                'score': 0,
                'user': {
                    'id': random.randint(1, 1000)
                },
                'retweeted': True
            }
        queue_copy = self.bot.post_queue.copy()
        self.bot.client.get_tweet = lambda x: queue_copy[x]

        self.bot.enter_contest()

        self.assertEqual(len(self.bot.post_queue), 0)
        self.assertFalse(self.bot.client.retweet.called)

        self.assertListEqual([x for x in range(10)], self.bot.ignore_list)

    def test_enter_contest_ignored_id(self):
        posts = 10
        self.bot.ignore_list = [0]
        for i in range(posts):
            self.bot.post_queue[i] = {
                'id': i,
                'full_text': 'test',
                'score': 0,
                'user': {
                    'id': 0
                }
            }

        self.bot.enter_contest()

        self.assertEqual(len(self.bot.post_queue), posts - 1)
        self.assertFalse(self.bot.client.retweet.called)

    def test_insert_post_to_queue(self):
        post = {
            'id': 0,
            'full_text': 'test',
            'user': {
                'id': random.randint(1, 1000),
                'screen_name': 'test'
            },
            'retweeted': False
        }

        self.bot._insert_post_to_queue(post)

        self.assertIn(post['id'], self.bot.post_queue)

    def test_insert_post_to_queue_ignore(self):
        post = {
            'id': 0,
            'full_text': 'test',
            'user': {
                'id': random.randint(1, 1000),
                'screen_name': 'test'
            },
            'retweeted': False
        }
        self.bot.ignore_list = [0]
        self.bot._insert_post_to_queue(post)

        self.assertNotIn(post['id'], self.bot.post_queue)

    def test_insert_post_to_queue_retweeted(self):
        post = {
            'id': 0,
            'full_text': 'test',
            'user': {
                'id': random.randint(1, 1000),
                'screen_name': 'test'
            },
            'retweeted': True
        }
        self.bot.ignore_list = [0]
        self.bot._insert_post_to_queue(post)

        self.assertNotIn(post['id'], self.bot.post_queue)

    def test_insert_post_to_queue_blocked_user(self):
        post = {
            'id': 0,
            'text': 'test',
            'user': {
                'id': 1,
                'screen_name': 'test'
            },
            'retweeted': False
        }
        self.bot.ignore_list = [1]
        self.bot._insert_post_to_queue(post)

        self.assertNotIn(post['id'], self.bot.post_queue)

    def test_insert_post_to_queue_that_has_a_quote_thats_deleted(self):
        with open(self.tests_path + '/fixtures/deleted_quote.json') as f:
            post = json.load(f)

        self.bot._insert_post_to_queue(post)

        self.assertNotIn(post['id'], self.bot.post_queue)

    def test_scan_new_contests(self):
        TwitterConfig.get()['search']['queries'] = ['test1']
        posts = list()
        for i in range(2):
            posts.append({
                'id': i,
                'full_text': 'test',
                'retweet_count': 1,
                'user': {
                    'id': random.randint(1, 1000),
                    'screen_name': 'test'
                },
                'retweeted': False,
                'created_at': 'Thu Oct 08 08:34:51 +0000 2015'
            })

        self.bot.client = MagicMock()
        self.bot.client.search_tweets.return_value = posts

        self.bot.scan_new_contests()

        self.bot.client.search_tweets.assert_called_once_with('test1', 50)
        self.assertEqual(len(self.bot.post_queue), 2)

    def test_scan_new_contests_with_language(self):
        TwitterConfig.get()['search']['queries'] = [OrderedDict()]
        TwitterConfig.get()['search']['queries'][0]['test1'] = None
        TwitterConfig.get()['search']['queries'][0]['lang'] = 'el'

        posts = list()
        for i in range(2):
            posts.append({
                'id': i,
                'full_text': 'test',
                'retweet_count': 1,
                'user': {
                    'id': random.randint(1, 1000),
                    'screen_name': 'test'
                },
                'retweeted': False,
                'created_at': 'Thu Oct 08 08:34:51 +0000 2015'
            })

        self.bot.client = MagicMock()
        self.bot.client.search_tweets.return_value = posts

        self.bot.scan_new_contests()

        self.bot.client.search_tweets.assert_called_once_with('test1',
                                                              50,
                                                              language='el')
        self.assertEqual(len(self.bot.post_queue), 2)

    def test_check_new_mentions_empty(self):
        posts = [create_post()]
        self.bot.client.get_mentions_timeline = MagicMock(return_value=posts)

        self.bot.check_new_mentions()

        self.bot.client.get_mentions_timeline.assert_called_once_with(count=1)
        self.assertEqual(self.bot.last_mention, posts[0])

    def test_check_new_mentions(self):
        posts = [create_post()]
        self.bot.client.get_mentions_timeline = MagicMock(return_value=posts)
        self.bot.last_mention = create_post()
        last_id = self.bot.last_mention['id']

        self.bot.check_new_mentions()

        self.bot.client.get_mentions_timeline.assert_called_once_with(
            since_id=last_id)
        self.assertEqual(self.bot.last_mention, posts[0])
        self.assertTrue(
            NotficationService.return_value.send_notification.called)

    def test_check_new_mentions_no_notifiers_enabled(self):

        self.bot.client.get_mentions_timeline = MagicMock()
        self.bot.notification = MagicMock()
        self.bot.notification.is_enabled.return_value = False
        NotficationService.reset_mock()

        self.bot.check_new_mentions()

        self.assertFalse(self.bot.client.get_mentions_timeline.called)
        self.assertFalse(
            NotficationService.return_value.send_notification.called)
        self.assertTrue(self.bot.notification.is_enabled)
예제 #7
0
 def setUp(self, config_mock, ignore_list_mock, client_mock):
     self.config = config_mock
     self.client = client_mock
     self.bot = Yatcobot('test')
예제 #8
0
class TestBot(unittest.TestCase):

    tests_path = path = os.path.dirname(os.path.abspath(__file__))

    @patch('yatcobot.bot.TwitterClient')
    @patch('yatcobot.bot.IgnoreList')
    @patch('yatcobot.bot.Config')
    def setUp(self, config_mock, ignore_list_mock, client_mock):
        self.config = config_mock
        self.client = client_mock
        self.bot = Yatcobot('test')

    def test_get_original_tweet_no_retweet(self):
        post = {'id': 1000}
        original = self.bot._get_original_tweet(post)
        self.assertEqual(post, original)

    def test_get_original_tweet_retweet(self):
        post = {'id': 1000, 'retweeted_status': {'id': 1001}}
        original = self.bot._get_original_tweet(post)
        self.assertEqual(post['retweeted_status'], original)

    def test_get_quoted_tweet_similar(self):
        quoted = {'id': 1, 'text': 'test'}
        post = {'id': 2, 'text': 'test', 'quoted_status': quoted}
        quoted_post_full = {'id': 1, 'text': 'test', 'user': {'id:1'}}
        self.bot.client.get_tweet.return_value = quoted_post_full

        r = self.bot._get_quoted_tweet(post)
        self.assertEqual(r, quoted_post_full)

    def test_get_quoted_tweet_quote_of_quotes(self):

        def mock_return(id):
            return mock_return.posts[id]
        mock_return.posts = dict()
        mock_return.posts[1] = {'id': 1, 'text': 'test', 'user': {'id:1'}}
        mock_return.posts[2] = {'id': 2, 'text': 'test', 'quoted_status': mock_return.posts[1]}
        mock_return.posts[3] = {'id': 3, 'text': 'test', 'quoted_status': mock_return.posts[2]}

        self.bot.client.get_tweet.side_effect = mock_return

        r = self.bot._get_quoted_tweet(mock_return.posts[3])
        self.assertEqual(r, mock_return.posts[1])

    def test_get_quoted_tweet_not_similar(self):
        quoted = {'id': 1, 'text': 'test'}
        post = {'id': 2, 'text': 'test sdfsdfsf', 'quoted_status': quoted}
        quoted_post_full = {'id': 1, 'text': 'test', 'user': {'id:1'}}
        self.bot.client.get_tweet.return_value = quoted_post_full

        r = self.bot._get_quoted_tweet(post)
        self.assertEqual(r, post)

    def test_get_quoted_tweet_real_post(self):
        with open(self.tests_path + '/fixtures/post_with_quote.json') as f:
            post = json.load(f)
        quoted_post_full = post.copy()
        quoted_post_full['user'] = {'id': 1}
        self.bot.client.get_tweet.return_value = quoted_post_full

        r = self.bot._get_quoted_tweet(post)
        self.assertEqual(r, quoted_post_full)

    def test_clear_queue_empty(self):
        Config.max_queue = 60
        self.bot.post_queue = MagicMock()
        self.bot.post_queue.__len__.return_value = 0
        self.bot.clear_queue()
        self.assertFalse(self.bot.post_queue.popitem.called)

    def test_clear_queue_full(self):
        self.config.max_queue = 60
        self.bot.post_queue = MagicMock()
        self.bot.post_queue.__len__.return_value = self.config.max_queue + 1

        self.bot.clear_queue()
        self.assertTrue(self.bot.post_queue.popitem.called)
        self.bot.post_queue.popitem.assert_called_with()

    def test_remove_oldest_follow_empty(self):
        follows = [x for x in range(Config.max_follows - 1)]
        self.bot.client.get_friends_ids.return_value = follows
        self.bot.remove_oldest_follow()
        self.assertFalse(self.bot.client.unfollow.called)

    def test_remove_oldest_follow_full(self):
        follows = [x for x in range(Config.max_follows + 1)]
        self.bot.client.get_friends_ids.return_value = follows
        self.bot.remove_oldest_follow()
        self.bot.client.unfollow.assert_called_with(Config.max_follows)

    def test_update_blocked_users(self):
        users = [x for x in range(10)]
        self.bot.ignore_list = list()
        self.bot.client.get_blocks.return_value = users
        self.bot.update_blocked_users()
        self.assertEqual(users, self.bot.ignore_list)

    def test_run(self):
        mock_scheduler = MagicMock(PeriodicScheduler)
        self.bot.scheduler = mock_scheduler
        self.bot.run()
        self.assertEqual(mock_scheduler.enter.call_count, 5)
        self.assertEqual(mock_scheduler.enter_random.call_count, 1)
        self.assertTrue(mock_scheduler.run.called)

    def test_enter_contest_simple_post(self):
        posts = 10
        for i in range(posts):
            self.bot.post_queue[i] = {'id': i, 'text': 'test', 'score': 0, 'user': {'id': random.randint(1, 1000), 'screen_name': 'test'}}

        self.bot.enter_contest()

        self.assertEqual(len(self.bot.post_queue), posts - 1)
        self.assertTrue(self.bot.client.retweet.called)
        self.bot.client.retweet.assert_called_with(0)

    def test_enter_contest_alredy_retweeted(self):
        posts = 10
        self.bot.ignore_list = list()
        for i in range(posts):
            self.bot.post_queue[i] = {'id': i, 'text': 'test', 'score': 0, 'user': {'id': random.randint(1, 1000)}}
        self.bot.client.retweet.side_effect = TwitterClientRetweetedException()

        self.bot.enter_contest()

        self.assertEqual(len(self.bot.post_queue), posts - 1)
        self.assertTrue(self.bot.client.retweet.called)
        self.bot.client.retweet.assert_called_with(0)

        self.assertIn(0, self.bot.ignore_list)

    def test_enter_contest_ignored_id(self):
        posts = 10
        self.bot.ignore_list = [0]
        for i in range(posts):
            self.bot.post_queue[i] = {'id': i, 'text': 'test', 'score': 0, 'user': {'id': 0}}

        self.bot.enter_contest()

        self.assertEqual(len(self.bot.post_queue), posts - 1)
        self.assertFalse(self.bot.client.retweet.called)

    def test_insert_post_to_queue(self):
        post = {'id': 0, 'text': 'test', 'user': {'id': random.randint(1, 1000), 'screen_name': 'test'}, 'retweeted': False}

        self.bot._insert_post_to_queue(post)

        self.assertIn(post['id'], self.bot.post_queue)

    def test_insert_post_to_queue_ignore(self):
        post = {'id': 0, 'text': 'test', 'user': {'id': random.randint(1, 1000), 'screen_name': 'test'}, 'retweeted': False}
        self.bot.ignore_list = [0]
        self.bot._insert_post_to_queue(post)

        self.assertNotIn(post['id'], self.bot.post_queue)

    def test_insert_post_to_queue_retweeted(self):
        post = {'id': 0, 'text': 'test', 'user': {'id': random.randint(1, 1000), 'screen_name': 'test'}, 'retweeted': True}
        self.bot.ignore_list = [0]
        self.bot._insert_post_to_queue(post)

        self.assertNotIn(post['id'], self.bot.post_queue)

    def test_insert_post_to_queue_blocked_user(self):
        post = {'id': 0, 'text': 'test', 'user': {'id': 1, 'screen_name': 'test'}, 'retweeted': False}
        self.bot.ignore_list = [1]
        self.bot._insert_post_to_queue(post)

        self.assertNotIn(post['id'], self.bot.post_queue)

    def test_insert_post_to_queue_that_has_a_quote_thats_deleted(self):
        with open(self.tests_path + '/fixtures/deleted_quote.json') as f:
            post = json.load(f)

        self.bot._insert_post_to_queue(post)

        self.assertNotIn(post['id'], self.bot.post_queue)

    def test_scan_new_contests(self):
        Config.search_queries = ['test1']
        posts = list()
        for i in range(2):
            posts.append({'id': i, 'text': 'test', 'retweet_count': 1,
                          'user': {'id': random.randint(1, 1000), 'screen_name': 'test'}, 'retweeted': False,
                          'created_at':'Thu Oct 08 08:34:51 +0000 2015'})

        self.bot.client = MagicMock()
        self.bot.client.search_tweets.return_value = posts

        self.bot.scan_new_contests()

        self.bot.client.search_tweets.assert_called_once_with('test1', 50)
        self.assertEqual(len(self.bot.post_queue), 2)

    def test_favorite(self):
        Config.fav_keywords = [' favorite ']
        self.bot.client = MagicMock()
        post = ({'id': 0, 'text': 'test favorite tests', 'user': {'id': random.randint(1, 1000), 'screen_name': 'test'}, 'retweeted': False})

        self.bot.check_for_favorite(post)

        self.bot.client.favorite.assert_called_once_with(post['id'])

    def test_follow(self):
        Config.follow_keywords = [' follow ']
        self.bot.client = MagicMock()
        post = ({'id': 0, 'text': 'test follow tests', 'user': {'id': random.randint(1, 1000), 'screen_name': 'test'}, 'retweeted': False})

        self.bot.check_for_follow(post)

        self.bot.client.follow.assert_called_once_with(post['user']['screen_name'])

    def test_get_keyword_mutations(self):
        keyword = 'keyword'
        target_mutations = ['#keyword', ' keyword ', '.keyword', 'keyword ', ' keyword', 'keyword.', ',keyword', 'keyword,']
        mutations = self.bot._get_keyword_mutations(keyword)
        self.assertEqual(len(mutations), len(target_mutations))
        for mutation in mutations:
            self.assertIn(mutation, target_mutations)

    def test_check_new_mentions_empty(self):
        posts = [create_post()]
        self.bot.client.get_mentions_timeline = MagicMock(return_value=posts)

        self.bot.check_new_mentions()

        self.bot.client.get_mentions_timeline.assert_called_once_with(count=1)
        self.assertEqual(self.bot.last_mention, posts[0])

    def test_check_new_mentions(self):
        posts = [create_post()]
        self.bot.client.get_mentions_timeline = MagicMock(return_value=posts)
        self.bot.last_mention = create_post()
        last_id = self.bot.last_mention['id']

        self.bot.check_new_mentions()

        self.bot.client.get_mentions_timeline.assert_called_once_with(since_id=last_id)
        self.assertEqual(self.bot.last_mention, posts[0])
        self.assertTrue(NotficationService.return_value.send_notification.called)

    def test_check_new_mentions_no_notifiers_enabled(self):

        self.bot.client.get_mentions_timeline = MagicMock()
        self.bot.notification = MagicMock()
        self.bot.notification.is_enabled.return_value = False
        NotficationService.reset_mock()

        self.bot.check_new_mentions()

        self.assertFalse(self.bot.client.get_mentions_timeline.called)
        self.assertFalse(NotficationService.return_value.send_notification.called)
        self.assertTrue(self.bot.notification.is_enabled)
예제 #9
0
 def setUp(self, config_mock, ignore_list_mock, client_mock):
     self.config = config_mock
     self.client = client_mock
     self.bot = Yatcobot('test')
예제 #10
0
class TestBot(unittest.TestCase):

    tests_path = path = os.path.dirname(os.path.abspath(__file__))

    @patch('yatcobot.bot.TwitterClient')
    @patch('yatcobot.bot.IgnoreList')
    @patch('yatcobot.bot.Config')
    def setUp(self, config_mock, ignore_list_mock, client_mock):
        self.config = config_mock
        self.client = client_mock
        self.bot = Yatcobot('test')

    def test_get_original_tweet_no_retweet(self):
        post = {'id': 1000}
        original = self.bot._get_original_tweet(post)
        self.assertEqual(post, original)

    def test_get_original_tweet_retweet(self):
        post = {'id': 1000, 'retweeted_status': {'id': 1001}}
        original = self.bot._get_original_tweet(post)
        self.assertEqual(post['retweeted_status'], original)

    def test_get_quoted_tweet_similar(self):
        quoted = {'id': 1, 'text': 'test'}
        post = {'id': 2, 'text': 'test', 'quoted_status': quoted}
        quoted_post_full = {'id': 1, 'text': 'test', 'user': {'id:1'}}
        self.bot.client.get_tweet.return_value = quoted_post_full

        r = self.bot._get_quoted_tweet(post)
        self.assertEqual(r, quoted_post_full)

    def test_get_quoted_tweet_quote_of_quotes(self):
        def mock_return(id):
            return mock_return.posts[id]

        mock_return.posts = dict()
        mock_return.posts[1] = {'id': 1, 'text': 'test', 'user': {'id:1'}}
        mock_return.posts[2] = {
            'id': 2,
            'text': 'test',
            'quoted_status': mock_return.posts[1]
        }
        mock_return.posts[3] = {
            'id': 3,
            'text': 'test',
            'quoted_status': mock_return.posts[2]
        }

        self.bot.client.get_tweet.side_effect = mock_return

        r = self.bot._get_quoted_tweet(mock_return.posts[3])
        self.assertEqual(r, mock_return.posts[1])

    def test_get_quoted_tweet_not_similar(self):
        quoted = {'id': 1, 'text': 'test'}
        post = {'id': 2, 'text': 'test sdfsdfsf', 'quoted_status': quoted}
        quoted_post_full = {'id': 1, 'text': 'test', 'user': {'id:1'}}
        self.bot.client.get_tweet.return_value = quoted_post_full

        r = self.bot._get_quoted_tweet(post)
        self.assertEqual(r, post)

    def test_get_quoted_tweet_real_post(self):
        with open(self.tests_path + '/fixtures/post_with_quote.json') as f:
            post = json.load(f)
        quoted_post_full = post.copy()
        quoted_post_full['user'] = {'id': 1}
        self.bot.client.get_tweet.return_value = quoted_post_full

        r = self.bot._get_quoted_tweet(post)
        self.assertEqual(r, quoted_post_full)

    def test_clear_queue_empty(self):
        Config.max_queue = 60
        self.bot.post_queue = MagicMock()
        self.bot.post_queue.__len__.return_value = 0
        self.bot.clear_queue()
        self.assertFalse(self.bot.post_queue.popitem.called)

    def test_clear_queue_full(self):
        self.config.max_queue = 60
        self.bot.post_queue = MagicMock()
        self.bot.post_queue.__len__.return_value = self.config.max_queue + 1

        self.bot.clear_queue()
        self.assertTrue(self.bot.post_queue.popitem.called)
        self.bot.post_queue.popitem.assert_called_with()

    def test_remove_oldest_follow_empty(self):
        follows = [x for x in range(Config.max_follows - 1)]
        self.bot.client.get_friends_ids.return_value = follows
        self.bot.remove_oldest_follow()
        self.assertFalse(self.bot.client.unfollow.called)

    def test_remove_oldest_follow_full(self):
        follows = [x for x in range(Config.max_follows + 1)]
        self.bot.client.get_friends_ids.return_value = follows
        self.bot.remove_oldest_follow()
        self.bot.client.unfollow.assert_called_with(Config.max_follows)

    def test_update_blocked_users(self):
        users = [x for x in range(10)]
        self.bot.ignore_list = list()
        self.bot.client.get_blocks.return_value = users
        self.bot.update_blocked_users()
        self.assertEqual(users, self.bot.ignore_list)

    def test_run(self):
        mock_scheduler = MagicMock(PeriodicScheduler)
        self.bot.scheduler = mock_scheduler
        self.bot.run()
        self.assertEqual(mock_scheduler.enter.call_count, 5)
        self.assertEqual(mock_scheduler.enter_random.call_count, 1)
        self.assertTrue(mock_scheduler.run.called)

    def test_enter_contest_simple_post(self):
        posts = 10
        for i in range(posts):
            self.bot.post_queue[i] = {
                'id': i,
                'text': 'test',
                'score': 0,
                'user': {
                    'id': random.randint(1, 1000),
                    'screen_name': 'test'
                }
            }

        self.bot.enter_contest()

        self.assertEqual(len(self.bot.post_queue), posts - 1)
        self.assertTrue(self.bot.client.retweet.called)
        self.bot.client.retweet.assert_called_with(0)

    def test_enter_contest_alredy_retweeted(self):
        posts = 10
        self.bot.ignore_list = list()
        for i in range(posts):
            self.bot.post_queue[i] = {
                'id': i,
                'text': 'test',
                'score': 0,
                'user': {
                    'id': random.randint(1, 1000)
                }
            }
        self.bot.client.retweet.side_effect = TwitterClientRetweetedException()

        self.bot.enter_contest()

        self.assertEqual(len(self.bot.post_queue), posts - 1)
        self.assertTrue(self.bot.client.retweet.called)
        self.bot.client.retweet.assert_called_with(0)

        self.assertIn(0, self.bot.ignore_list)

    def test_enter_contest_ignored_id(self):
        posts = 10
        self.bot.ignore_list = [0]
        for i in range(posts):
            self.bot.post_queue[i] = {
                'id': i,
                'text': 'test',
                'score': 0,
                'user': {
                    'id': 0
                }
            }

        self.bot.enter_contest()

        self.assertEqual(len(self.bot.post_queue), posts - 1)
        self.assertFalse(self.bot.client.retweet.called)

    def test_insert_post_to_queue(self):
        post = {
            'id': 0,
            'text': 'test',
            'user': {
                'id': random.randint(1, 1000),
                'screen_name': 'test'
            },
            'retweeted': False
        }

        self.bot._insert_post_to_queue(post)

        self.assertIn(post['id'], self.bot.post_queue)

    def test_insert_post_to_queue_ignore(self):
        post = {
            'id': 0,
            'text': 'test',
            'user': {
                'id': random.randint(1, 1000),
                'screen_name': 'test'
            },
            'retweeted': False
        }
        self.bot.ignore_list = [0]
        self.bot._insert_post_to_queue(post)

        self.assertNotIn(post['id'], self.bot.post_queue)

    def test_insert_post_to_queue_retweeted(self):
        post = {
            'id': 0,
            'text': 'test',
            'user': {
                'id': random.randint(1, 1000),
                'screen_name': 'test'
            },
            'retweeted': True
        }
        self.bot.ignore_list = [0]
        self.bot._insert_post_to_queue(post)

        self.assertNotIn(post['id'], self.bot.post_queue)

    def test_insert_post_to_queue_blocked_user(self):
        post = {
            'id': 0,
            'text': 'test',
            'user': {
                'id': 1,
                'screen_name': 'test'
            },
            'retweeted': False
        }
        self.bot.ignore_list = [1]
        self.bot._insert_post_to_queue(post)

        self.assertNotIn(post['id'], self.bot.post_queue)

    def test_insert_post_to_queue_that_has_a_quote_thats_deleted(self):
        with open(self.tests_path + '/fixtures/deleted_quote.json') as f:
            post = json.load(f)

        self.bot._insert_post_to_queue(post)

        self.assertNotIn(post['id'], self.bot.post_queue)

    def test_scan_new_contests(self):
        Config.search_queries = ['test1']
        posts = list()
        for i in range(2):
            posts.append({
                'id': i,
                'text': 'test',
                'retweet_count': 1,
                'user': {
                    'id': random.randint(1, 1000),
                    'screen_name': 'test'
                },
                'retweeted': False,
                'created_at': 'Thu Oct 08 08:34:51 +0000 2015'
            })

        self.bot.client = MagicMock()
        self.bot.client.search_tweets.return_value = posts

        self.bot.scan_new_contests()

        self.bot.client.search_tweets.assert_called_once_with('test1', 50)
        self.assertEqual(len(self.bot.post_queue), 2)

    def test_favorite(self):
        Config.fav_keywords = [' favorite ']
        self.bot.client = MagicMock()
        post = ({
            'id': 0,
            'text': 'test favorite tests',
            'user': {
                'id': random.randint(1, 1000),
                'screen_name': 'test'
            },
            'retweeted': False
        })

        self.bot.check_for_favorite(post)

        self.bot.client.favorite.assert_called_once_with(post['id'])

    def test_follow(self):
        Config.follow_keywords = [' follow ']
        self.bot.client = MagicMock()
        post = ({
            'id': 0,
            'text': 'test follow tests',
            'user': {
                'id': random.randint(1, 1000),
                'screen_name': 'test'
            },
            'retweeted': False
        })

        self.bot.check_for_follow(post)

        self.bot.client.follow.assert_called_once_with(
            post['user']['screen_name'])

    def test_get_keyword_mutations(self):
        keyword = 'keyword'
        target_mutations = [
            '#keyword', ' keyword ', '.keyword', 'keyword ', ' keyword',
            'keyword.', ',keyword', 'keyword,'
        ]
        mutations = self.bot._get_keyword_mutations(keyword)
        self.assertEqual(len(mutations), len(target_mutations))
        for mutation in mutations:
            self.assertIn(mutation, target_mutations)

    def test_check_new_mentions_empty(self):
        posts = [create_post()]
        self.bot.client.get_mentions_timeline = MagicMock(return_value=posts)

        self.bot.check_new_mentions()

        self.bot.client.get_mentions_timeline.assert_called_once_with(count=1)
        self.assertEqual(self.bot.last_mention, posts[0])

    def test_check_new_mentions(self):
        posts = [create_post()]
        self.bot.client.get_mentions_timeline = MagicMock(return_value=posts)
        self.bot.last_mention = create_post()
        last_id = self.bot.last_mention['id']

        self.bot.check_new_mentions()

        self.bot.client.get_mentions_timeline.assert_called_once_with(
            since_id=last_id)
        self.assertEqual(self.bot.last_mention, posts[0])
        self.assertTrue(
            NotficationService.return_value.send_notification.called)

    def test_check_new_mentions_no_notifiers_enabled(self):

        self.bot.client.get_mentions_timeline = MagicMock()
        self.bot.notification = MagicMock()
        self.bot.notification.is_enabled.return_value = False
        NotficationService.reset_mock()

        self.bot.check_new_mentions()

        self.assertFalse(self.bot.client.get_mentions_timeline.called)
        self.assertFalse(
            NotficationService.return_value.send_notification.called)
        self.assertTrue(self.bot.notification.is_enabled)