7a0da7932b
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
135 lines
4.4 KiB
Python
135 lines
4.4 KiB
Python
"""Regression tests for session-rollback hygiene in LibraryRAGService.
|
|
|
|
Follow-up to #3827: the service's `index_document` and
|
|
`remove_document_from_rag` methods both open a thread-local session,
|
|
perform writes (`session.flush()` / `session.commit()`), and catch
|
|
exceptions in an outer ``except`` block. Without an explicit rollback
|
|
that catch leaves the shared session in ``PendingRollbackError`` state —
|
|
every subsequent ORM operation on the same thread cascades.
|
|
|
|
These tests force an exception inside the try-block and assert that
|
|
``session.rollback`` was called before the helper returned its error
|
|
dict.
|
|
"""
|
|
|
|
from unittest.mock import MagicMock, patch
|
|
|
|
|
|
_MOD = "local_deep_research.research_library.services.library_rag_service"
|
|
|
|
|
|
def _make_service(**overrides):
|
|
"""Instantiate LibraryRAGService with all heavy deps mocked out."""
|
|
with (
|
|
patch(f"{_MOD}.LocalEmbeddingManager") as _lem,
|
|
patch(f"{_MOD}.get_user_db_session"),
|
|
patch(f"{_MOD}.FileIntegrityManager"),
|
|
patch(f"{_MOD}.get_text_splitter"),
|
|
):
|
|
_lem.return_value.embeddings = MagicMock()
|
|
from local_deep_research.research_library.services.library_rag_service import (
|
|
LibraryRAGService,
|
|
)
|
|
|
|
defaults = dict(username="testuser", db_password="pw")
|
|
defaults.update(overrides)
|
|
return LibraryRAGService(**defaults)
|
|
|
|
|
|
def _ctx_yielding(session):
|
|
"""Context-manager mock that yields *session*."""
|
|
ctx = MagicMock()
|
|
ctx.__enter__ = MagicMock(return_value=session)
|
|
ctx.__exit__ = MagicMock(return_value=False)
|
|
return ctx
|
|
|
|
|
|
def _make_doc(text="Long text content for indexing test."):
|
|
doc = MagicMock()
|
|
doc.id = "doc-1"
|
|
doc.text_content = text
|
|
doc.title = "Test"
|
|
doc.filename = None
|
|
doc.original_url = "http://example.com/d"
|
|
doc.authors = None
|
|
doc.published_date = None
|
|
doc.doi = None
|
|
doc.arxiv_id = None
|
|
doc.pmid = None
|
|
doc.pmcid = None
|
|
doc.extraction_method = None
|
|
doc.word_count = None
|
|
return doc
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# index_document: rollback fires when the inner work raises.
|
|
# ---------------------------------------------------------------------------
|
|
|
|
|
|
@patch(f"{_MOD}.ensure_in_collection")
|
|
@patch(f"{_MOD}.get_user_db_session")
|
|
def test_index_document_rolls_back_session_on_exception(
|
|
mock_get_session, mock_ensure
|
|
):
|
|
"""If text-splitting or any inner step raises, the outer except must
|
|
call session.rollback() before returning the error dict."""
|
|
svc = _make_service()
|
|
|
|
session = MagicMock()
|
|
mock_get_session.return_value = _ctx_yielding(session)
|
|
|
|
session.query.return_value.filter_by.return_value.first.return_value = (
|
|
_make_doc()
|
|
)
|
|
mock_ensure.return_value = MagicMock(indexed=False, chunk_count=0)
|
|
|
|
# Force the inner work to raise — text_splitter is patched in
|
|
# _make_service, but make it explicit here.
|
|
svc.text_splitter = MagicMock()
|
|
svc.text_splitter.split_documents.side_effect = RuntimeError(
|
|
"simulated splitter failure"
|
|
)
|
|
|
|
result = svc.index_document("doc-1", "coll-1")
|
|
|
|
assert result["status"] == "error"
|
|
session.rollback.assert_called_once()
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# remove_document_from_rag: rollback fires when commit (or anything before
|
|
# it) raises.
|
|
# ---------------------------------------------------------------------------
|
|
|
|
|
|
@patch(f"{_MOD}.get_user_db_session")
|
|
def test_remove_document_from_rag_rolls_back_session_on_exception(
|
|
mock_get_session,
|
|
):
|
|
"""If session.commit() (or earlier work) raises, the outer except
|
|
must call session.rollback()."""
|
|
svc = _make_service()
|
|
|
|
session = MagicMock()
|
|
mock_get_session.return_value = _ctx_yielding(session)
|
|
|
|
# First filter_by chain returns a non-None DocumentCollection so we
|
|
# enter the try block.
|
|
doc_collection = MagicMock(indexed=True, chunk_count=3)
|
|
session.query.return_value.filter_by.return_value.first.return_value = (
|
|
doc_collection
|
|
)
|
|
|
|
# Make the embedding-manager's chunk deletion raise inside the try
|
|
# block (mirrors a real DB / FAISS layer failure).
|
|
svc.embedding_manager = MagicMock()
|
|
svc.embedding_manager._delete_chunks_from_db.side_effect = RuntimeError(
|
|
"simulated chunk-delete failure"
|
|
)
|
|
|
|
result = svc.remove_document_from_rag("doc-1", "coll-1")
|
|
|
|
assert result["status"] == "error"
|
|
session.rollback.assert_called_once()
|