""" Tests for sentiment analysis worker. """ import pytest from unittest.mock import Mock, patch from sqlalchemy.orm import Session from app.workers.sentiment_worker import ( SentimentWorker, create_sentiment_worker ) class TestSentimentWorker: """Tests for SentimentWorker class.""" def test_initialization(self): """Test sentiment worker initialization.""" worker = SentimentWorker() # No specific initialization required for sentiment worker assert worker is not None @patch('app.workers.sentiment_worker.process_tweet_batch') @patch('app.workers.sentiment_worker.get_sentiment_by_entity') def test_execute_sentiment_analysis_task_twitter( self, mock_get_sentiment, mock_process_batch ): """Test executing a Twitter sentiment analysis task.""" # Create worker worker = SentimentWorker() # Mock database session mock_db = Mock(spec=Session) # Mock tweet query mock_tweets = [Mock()] * 100 mock_db.query.return_value.filter.return_value.all.return_value = mock_tweets # Mock existing sentiment (none exist) mock_get_sentiment.return_value = None # Mock batch processing mock_process_batch.return_value = [Mock()] * 100 # Mock calculate metrics with patch.object( worker, '_calculate_sentiment_metrics', return_value={ 'total_count': 100, 'positive_count': 60, 'negative_count': 20, 'neutral_count': 20, 'average_compound': 0.35 } ): # Execute task task = { 'match_id': 123, 'source': 'twitter', 'entity_ids': ['tweet1', 'tweet2'] } result = worker.execute_sentiment_analysis_task(task, mock_db) # Verify result assert result['analyzed_count'] == 100 assert result['status'] == 'success' assert result['metrics']['total_count'] == 100 assert result['metrics']['positive_count'] == 60 @patch('app.workers.sentiment_worker.process_reddit_post_batch') @patch('app.workers.sentiment_worker.get_sentiment_by_entity') def test_execute_sentiment_analysis_task_reddit( self, mock_get_sentiment, mock_process_batch ): """Test executing a Reddit sentiment analysis task.""" # Create worker worker = SentimentWorker() # Mock database session mock_db = Mock(spec=Session) # Mock Reddit post query mock_posts = [Mock()] * 50 mock_db.query.return_value.filter.return_value.all.return_value = mock_posts # Mock existing sentiment (none exist) mock_get_sentiment.return_value = None # Mock batch processing mock_process_batch.return_value = [Mock()] * 50 # Mock calculate metrics with patch.object( worker, '_calculate_sentiment_metrics', return_value={ 'total_count': 50, 'positive_count': 25, 'negative_count': 15, 'neutral_count': 10, 'average_compound': 0.2 } ): # Execute task task = { 'match_id': 456, 'source': 'reddit', 'entity_ids': ['post1', 'post2'] } result = worker.execute_sentiment_analysis_task(task, mock_db) # Verify result assert result['analyzed_count'] == 50 assert result['status'] == 'success' assert result['metrics']['total_count'] == 50 @patch('app.workers.sentiment_worker.get_sentiment_by_entity') def test_execute_sentiment_analysis_task_all_analyzed( self, mock_get_sentiment ): """Test executing task when all items already analyzed.""" worker = SentimentWorker() mock_db = Mock(spec=Session) # Mock tweets mock_tweets = [Mock()] * 100 mock_db.query.return_value.filter.return_value.all.return_value = mock_tweets # Mock existing sentiment (all exist) mock_get_sentiment.return_value = Mock() # Mock calculate metrics from existing with patch.object( worker, '_calculate_metrics_from_existing', return_value={ 'total_count': 100, 'average_compound': 0.4 } ): # Execute task task = { 'match_id': 123, 'source': 'twitter', 'entity_ids': ['tweet1', 'tweet2'] } result = worker.execute_sentiment_analysis_task(task, mock_db) # Verify result (0 new items analyzed) assert result['analyzed_count'] == 0 assert result['status'] == 'success' def test_execute_sentiment_analysis_task_unknown_source(self): """Test executing task with unknown source.""" worker = SentimentWorker() mock_db = Mock(spec=Session) # Execute task with unknown source task = { 'match_id': 123, 'source': 'unknown', 'entity_ids': ['item1'] } result = worker.execute_sentiment_analysis_task(task, mock_db) # Verify error result assert result['analyzed_count'] == 0 assert result['status'] == 'error' assert 'error' in result assert 'Unknown source' in result['error'] @patch('app.workers.sentiment_worker.process_tweet_batch') @patch('app.workers.sentiment_worker.get_sentiment_by_entity') def test_execute_sentiment_analysis_task_error_handling( self, mock_get_sentiment, mock_process_batch ): """Test error handling in sentiment analysis.""" worker = SentimentWorker() mock_db = Mock(spec=Session) # Mock tweets mock_tweets = [Mock()] * 10 mock_db.query.return_value.filter.return_value.all.return_value = mock_tweets # Mock no existing sentiment mock_get_sentiment.return_value = None # Mock processing error mock_process_batch.side_effect = Exception("Processing error") # Execute task task = { 'match_id': 123, 'source': 'twitter', 'entity_ids': ['tweet1', 'tweet2'] } result = worker.execute_sentiment_analysis_task(task, mock_db) # Verify error handling assert result['analyzed_count'] == 0 assert result['status'] == 'error' assert 'error' in result @patch('app.workers.sentiment_worker.get_sentiment_by_entity') def test_execute_twitter_sentiment_analysis_no_tweets( self, mock_get_sentiment ): """Test Twitter sentiment analysis when no tweets found.""" worker = SentimentWorker() mock_db = Mock(spec=Session) # Mock no tweets mock_db.query.return_value.filter.return_value.all.return_value = [] # Execute task result = worker._execute_twitter_sentiment_analysis( match_id=123, entity_ids=['tweet1', 'tweet2'], db=mock_db ) # Verify result assert result['analyzed_count'] == 0 assert result['status'] == 'success' assert result['metrics']['total_count'] == 0 class TestCreateSentimentWorker: """Tests for create_sentiment_worker factory function.""" def test_create_sentiment_worker(self): """Test creating a sentiment worker.""" worker = create_sentiment_worker() assert isinstance(worker, SentimentWorker)