chore: import upstream snapshot with attribution
OSV-Scanner (Scheduled) / scan-scheduled (push) Failing after 0s
Create Release / test-gate (push) Has been cancelled
Create Release / release-gate (push) Has been cancelled
Create Release / ci-gate (push) Has been cancelled
Create Release / version-check (push) Has been cancelled
Create Release / e2e-test-gate (push) Has been cancelled
Create Release / responsive-test-gate (push) Has been cancelled
Create Release / compat-test-gate (push) Has been cancelled
Create Release / compose-integration-gate (push) Has been cancelled
Create Release / vulture-gate (push) Has been cancelled
Create Release / build (push) Has been cancelled
Create Release / provenance (push) Has been cancelled
Create Release / prerelease-docker (push) Has been cancelled
Create Release / publish-docker (push) Has been cancelled
Create Release / create-release (push) Has been cancelled
Create Release / cleanup-changelog (push) Has been cancelled
Create Release / trigger-pypi (push) Has been cancelled
Create Release / monitor-pypi (push) Has been cancelled
Create Release / Clean up orphan prerelease tags and signatures (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [research-form] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [research-metrics] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [research-workflow] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [settings-core] (push) Has been cancelled
CodeQL Advanced / Analyze (javascript-typescript) (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [history-news] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [library] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [link-analytics] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [chat-core] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [chat-lifecycle] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [error-benchmark] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [settings-pages] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) (push) Has been cancelled
Docker Tests (Consolidated) / Accessibility Tests (push) Has been cancelled
Docker Tests (Consolidated) / LLM Unit Tests (push) Has been cancelled
Docker Tests (Consolidated) / LLM Example Tests (push) Has been cancelled
Docker Tests (Consolidated) / Production Image Smoke Test (push) Has been cancelled
Docker Tests (Consolidated) / Infrastructure Tests (push) Has been cancelled
OSSF Scorecard / OSSF Security Scorecard Analysis (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [mobile] (push) Has been cancelled
Backwards Compatibility / Verify Encryption Constants (push) Has been cancelled
Backwards Compatibility / PyPI Version Compatibility (push) Has been cancelled
Backwards Compatibility / Database Migration Tests (push) Has been cancelled
CodeQL Advanced / Analyze (python) (push) Has been cancelled
Docker Tests (Consolidated) / detect-changes (push) Has been cancelled
Docker Tests (Consolidated) / Build Test Image (push) Has been cancelled
Docker Tests (Consolidated) / All Pytest Tests + Coverage (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [accessibility] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [api-crud] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [auth-login] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [auth-pages] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [auth-register] (push) Has been cancelled
OSV-Scanner (Scheduled) / scan-scheduled (push) Failing after 0s
Create Release / test-gate (push) Has been cancelled
Create Release / release-gate (push) Has been cancelled
Create Release / ci-gate (push) Has been cancelled
Create Release / version-check (push) Has been cancelled
Create Release / e2e-test-gate (push) Has been cancelled
Create Release / responsive-test-gate (push) Has been cancelled
Create Release / compat-test-gate (push) Has been cancelled
Create Release / compose-integration-gate (push) Has been cancelled
Create Release / vulture-gate (push) Has been cancelled
Create Release / build (push) Has been cancelled
Create Release / provenance (push) Has been cancelled
Create Release / prerelease-docker (push) Has been cancelled
Create Release / publish-docker (push) Has been cancelled
Create Release / create-release (push) Has been cancelled
Create Release / cleanup-changelog (push) Has been cancelled
Create Release / trigger-pypi (push) Has been cancelled
Create Release / monitor-pypi (push) Has been cancelled
Create Release / Clean up orphan prerelease tags and signatures (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [research-form] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [research-metrics] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [research-workflow] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [settings-core] (push) Has been cancelled
CodeQL Advanced / Analyze (javascript-typescript) (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [history-news] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [library] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [link-analytics] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [chat-core] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [chat-lifecycle] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [error-benchmark] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [settings-pages] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) (push) Has been cancelled
Docker Tests (Consolidated) / Accessibility Tests (push) Has been cancelled
Docker Tests (Consolidated) / LLM Unit Tests (push) Has been cancelled
Docker Tests (Consolidated) / LLM Example Tests (push) Has been cancelled
Docker Tests (Consolidated) / Production Image Smoke Test (push) Has been cancelled
Docker Tests (Consolidated) / Infrastructure Tests (push) Has been cancelled
OSSF Scorecard / OSSF Security Scorecard Analysis (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [mobile] (push) Has been cancelled
Backwards Compatibility / Verify Encryption Constants (push) Has been cancelled
Backwards Compatibility / PyPI Version Compatibility (push) Has been cancelled
Backwards Compatibility / Database Migration Tests (push) Has been cancelled
CodeQL Advanced / Analyze (python) (push) Has been cancelled
Docker Tests (Consolidated) / detect-changes (push) Has been cancelled
Docker Tests (Consolidated) / Build Test Image (push) Has been cancelled
Docker Tests (Consolidated) / All Pytest Tests + Coverage (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [accessibility] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [api-crud] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [auth-login] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [auth-pages] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [auth-register] (push) Has been cancelled
This commit is contained in:
@@ -0,0 +1,346 @@
|
||||
"""
|
||||
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")
|
||||
Reference in New Issue
Block a user