test(ocr): round-6 — batch submit-error propagation test + import cleanup
Round 6 review (PR #910): - Add the missing propagation test: a transport error (httpx.ConnectError) from batch submit() propagates out of process() rather than being caught by the sync OCR try/except or falling back to a sync transcription — guards the intentional "opted into batch → procrastinate retry, not sync fallback" asymmetry. - Move the batch-test module imports (BatchPollResult, batch_ocr_store) to the top of test_ocr_processor.py, dropping the mid-file `# noqa: E402`. Deferred (reviewer: not actionable for this PR): extracting a lazy-init helper for the parallel _backend / _batch_client resolution quadruplets. 1653 unit tests pass; ruff + ty green. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
bb08245c91
commit
210a234c11
@@ -4,9 +4,12 @@ from types import SimpleNamespace
|
||||
from typing import Any
|
||||
|
||||
import anyio
|
||||
import httpx
|
||||
import pytest
|
||||
|
||||
from nextcloud_mcp_server.document_processors import ocr
|
||||
from nextcloud_mcp_server.embedding.gateway_batch_client import BatchPollResult
|
||||
from nextcloud_mcp_server.vector import batch_ocr_store as _bos
|
||||
|
||||
pytestmark = pytest.mark.unit
|
||||
|
||||
@@ -274,11 +277,6 @@ def test_batch_identity_extracts_tuple_and_defaults_etag():
|
||||
)
|
||||
|
||||
|
||||
from nextcloud_mcp_server.embedding.gateway_batch_client import ( # noqa: E402
|
||||
BatchPollResult,
|
||||
)
|
||||
from nextcloud_mcp_server.vector import batch_ocr_store as _bos # noqa: E402
|
||||
|
||||
_IDENTITY = {"user_id": "u1", "doc_id": "d1", "doc_type": "file", "etag": "v1"}
|
||||
|
||||
|
||||
@@ -481,3 +479,34 @@ async def test_batch_falls_back_to_sync_when_no_identity(monkeypatch):
|
||||
r = await ocr.OcrProcessor().process(b"%PDF", "application/pdf", options=None)
|
||||
assert r.success is True and r.text == "sync text"
|
||||
assert client.submitted == [] # never attempted batch
|
||||
|
||||
|
||||
async def test_batch_submit_transport_error_propagates_not_caught(monkeypatch):
|
||||
# Opted into batch: a transport error from submit() must propagate (to
|
||||
# procrastinate for a durable retry), NOT be caught by the sync OCR
|
||||
# try/except or fall back to a surprise sync transcription. Guards the
|
||||
# intentional asymmetry documented in process().
|
||||
class _DownClient:
|
||||
submitted: list = []
|
||||
|
||||
async def submit(self, content, mime_type, custom_id):
|
||||
raise httpx.ConnectError("gateway down")
|
||||
|
||||
async def poll(self, job_id): # pragma: no cover - not reached
|
||||
raise AssertionError("poll should not be called")
|
||||
|
||||
sync_backend_used = False
|
||||
|
||||
def _build_backend(_s):
|
||||
nonlocal sync_backend_used
|
||||
sync_backend_used = True
|
||||
return None
|
||||
|
||||
monkeypatch.setattr(ocr, "build_ocr_backend", _build_backend)
|
||||
_wire_batch(monkeypatch, client=_DownClient(), store=_FakeStore())
|
||||
|
||||
with pytest.raises(httpx.ConnectError):
|
||||
await ocr.OcrProcessor().process(
|
||||
b"%PDF", "application/pdf", options=dict(_IDENTITY)
|
||||
)
|
||||
assert sync_backend_used is False # never fell back to the sync path
|
||||
|
||||
Reference in New Issue
Block a user