""" Tests for web/queue/manager.py Tests cover: - QueueManager.add_to_queue - QueueManager.get_queue_position - QueueManager.remove_from_queue - QueueManager.get_user_queue """ from contextlib import contextmanager from unittest.mock import MagicMock, patch import pytest from local_deep_research.database.session_context import DatabaseSessionError def _mock_user_db_session(mock_session): """Create a mock context manager that yields the given session.""" @contextmanager def _ctx(username=None, password=None): yield mock_session return _ctx def _mock_user_db_session_error(): """Create a mock context manager that raises DatabaseSessionError.""" @contextmanager def _ctx(username=None, password=None): raise DatabaseSessionError("No database connection") yield # noqa: unreachable — needed for generator syntax return _ctx class TestQueueManagerAddToQueue: """Tests for QueueManager.add_to_queue method.""" def test_add_to_queue_success(self): """Test successful addition to queue.""" mock_session = MagicMock() # Mock query chain for max position mock_query = MagicMock() mock_query.filter_by.return_value.scalar.return_value = 0 mock_session.query.return_value = mock_query with patch( "local_deep_research.web.queue.manager.get_user_db_session", _mock_user_db_session(mock_session), ): with patch( "local_deep_research.web.queue.manager.queue_processor" ) as mock_processor: from local_deep_research.web.queue.manager import ( QueueManager, ) result = QueueManager.add_to_queue( username="testuser", research_id="test-id-123", query="test query", mode="detailed", settings={"key": "value"}, ) assert result == 1 mock_session.add.assert_called_once() mock_session.commit.assert_called_once() mock_processor.notify_research_queued.assert_called_once_with( "testuser", "test-id-123" ) def test_add_to_queue_no_connection(self): """Test add_to_queue raises DatabaseSessionError when no connection.""" with patch( "local_deep_research.web.queue.manager.get_user_db_session", _mock_user_db_session_error(), ): from local_deep_research.web.queue.manager import QueueManager with pytest.raises(DatabaseSessionError): QueueManager.add_to_queue( username="testuser", research_id="test-id-123", query="test query", mode="detailed", settings={}, ) def test_add_to_queue_with_existing_items(self): """Test add_to_queue with existing items in queue.""" mock_session = MagicMock() # Mock query chain for max position - already has 3 items mock_query = MagicMock() mock_query.filter_by.return_value.scalar.return_value = 3 mock_session.query.return_value = mock_query with patch( "local_deep_research.web.queue.manager.get_user_db_session", _mock_user_db_session(mock_session), ): with patch("local_deep_research.web.queue.manager.queue_processor"): from local_deep_research.web.queue.manager import ( QueueManager, ) result = QueueManager.add_to_queue( username="testuser", research_id="test-id-456", query="another query", mode="quick", settings={}, ) # Position should be 4 (max + 1) assert result == 4 class TestQueueManagerGetQueuePosition: """Tests for QueueManager.get_queue_position method.""" def test_get_queue_position_success(self): """Test getting queue position successfully.""" mock_session = MagicMock() # Mock queued research item mock_queued = MagicMock() mock_queued.position = 3 # Setup query chain mock_query = MagicMock() mock_filter = MagicMock() mock_filter.first.return_value = mock_queued mock_filter.count.return_value = 2 # 2 items ahead mock_query.filter_by.return_value = mock_filter mock_query.filter.return_value = mock_filter mock_session.query.return_value = mock_query with patch( "local_deep_research.web.queue.manager.get_user_db_session", _mock_user_db_session(mock_session), ): from local_deep_research.web.queue.manager import QueueManager result = QueueManager.get_queue_position( username="testuser", research_id="test-id-123" ) # Position should be ahead_count + 1 assert result == 3 def test_get_queue_position_not_found(self): """Test get_queue_position when research not in queue.""" mock_session = MagicMock() mock_query = MagicMock() mock_query.filter_by.return_value.first.return_value = None mock_session.query.return_value = mock_query with patch( "local_deep_research.web.queue.manager.get_user_db_session", _mock_user_db_session(mock_session), ): from local_deep_research.web.queue.manager import QueueManager result = QueueManager.get_queue_position( username="testuser", research_id="nonexistent" ) assert result is None def test_get_queue_position_no_connection(self): """Test get_queue_position raises DatabaseSessionError when no connection.""" with patch( "local_deep_research.web.queue.manager.get_user_db_session", _mock_user_db_session_error(), ): from local_deep_research.web.queue.manager import QueueManager with pytest.raises(DatabaseSessionError): QueueManager.get_queue_position( username="testuser", research_id="test-id-123" ) class TestQueueManagerRemoveFromQueue: """Tests for QueueManager.remove_from_queue method.""" def test_remove_from_queue_success(self): """Test successful removal from queue.""" mock_session = MagicMock() # Mock queued research item mock_queued = MagicMock() mock_queued.position = 2 mock_query = MagicMock() mock_query.filter_by.return_value.first.return_value = mock_queued mock_query.filter.return_value.update.return_value = None mock_session.query.return_value = mock_query with patch( "local_deep_research.web.queue.manager.get_user_db_session", _mock_user_db_session(mock_session), ): from local_deep_research.web.queue.manager import QueueManager result = QueueManager.remove_from_queue( username="testuser", research_id="test-id-123" ) assert result is True mock_session.delete.assert_called_once_with(mock_queued) mock_session.commit.assert_called_once() def test_remove_from_queue_not_found(self): """Test remove_from_queue when research not in queue.""" mock_session = MagicMock() mock_query = MagicMock() mock_query.filter_by.return_value.first.return_value = None mock_session.query.return_value = mock_query with patch( "local_deep_research.web.queue.manager.get_user_db_session", _mock_user_db_session(mock_session), ): from local_deep_research.web.queue.manager import QueueManager result = QueueManager.remove_from_queue( username="testuser", research_id="nonexistent" ) assert result is False def test_remove_from_queue_no_connection(self): """Test remove_from_queue raises DatabaseSessionError when no connection.""" with patch( "local_deep_research.web.queue.manager.get_user_db_session", _mock_user_db_session_error(), ): from local_deep_research.web.queue.manager import QueueManager with pytest.raises(DatabaseSessionError): QueueManager.remove_from_queue( username="testuser", research_id="test-id-123" ) class TestQueueManagerGetUserQueue: """Tests for QueueManager.get_user_queue method.""" def test_get_user_queue_success(self): """Test getting user queue successfully.""" mock_session = MagicMock() # Mock queued items from datetime import datetime mock_item1 = MagicMock() mock_item1.research_id = "id-1" mock_item1.query = "query 1" mock_item1.mode = "detailed" mock_item1.position = 1 mock_item1.created_at = datetime(2025, 1, 1, 12, 0, 0) mock_item1.is_processing = False mock_item2 = MagicMock() mock_item2.research_id = "id-2" mock_item2.query = "query 2" mock_item2.mode = "quick" mock_item2.position = 2 mock_item2.created_at = None mock_item2.is_processing = True mock_research1 = MagicMock() mock_research2 = MagicMock() def query_side_effect(model): q = MagicMock() if "QueuedResearch" in str(model): q.filter_by.return_value.order_by.return_value.all.return_value = [ mock_item1, mock_item2, ] else: # ResearchHistory # Return research on first call, then second q.filter_by.return_value.first.side_effect = [ mock_research1, mock_research2, ] return q mock_session.query.side_effect = query_side_effect with patch( "local_deep_research.web.queue.manager.get_user_db_session", _mock_user_db_session(mock_session), ): from local_deep_research.web.queue.manager import QueueManager result = QueueManager.get_user_queue(username="testuser") assert len(result) == 2 assert result[0]["research_id"] == "id-1" assert result[0]["query"] == "query 1" assert result[0]["mode"] == "detailed" assert result[0]["position"] == 1 assert result[0]["is_processing"] is False assert result[1]["research_id"] == "id-2" assert result[1]["created_at"] is None def test_get_user_queue_empty(self): """Test get_user_queue when queue is empty.""" mock_session = MagicMock() mock_query = MagicMock() mock_query.filter_by.return_value.order_by.return_value.all.return_value = [] mock_session.query.return_value = mock_query with patch( "local_deep_research.web.queue.manager.get_user_db_session", _mock_user_db_session(mock_session), ): from local_deep_research.web.queue.manager import QueueManager result = QueueManager.get_user_queue(username="testuser") assert result == [] def test_get_user_queue_no_connection(self): """Test get_user_queue raises DatabaseSessionError when no connection.""" with patch( "local_deep_research.web.queue.manager.get_user_db_session", _mock_user_db_session_error(), ): from local_deep_research.web.queue.manager import QueueManager with pytest.raises(DatabaseSessionError): QueueManager.get_user_queue(username="testuser")