Files
wehub-resource-sync 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
chore: import upstream snapshot with attribution
2026-07-13 13:08:55 +08:00

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()