test(ingest): use https test gateway URLs; doc fixes (review round 6)
Resolves the SonarCloud quality gate (new_security_hotspots_reviewed) — the 7 TO_REVIEW hotspots were all `http://gw` fake gateway URLs in test_ocr_processor.py flagged "use https". Switched the test fixtures to `https://gw` (identical for a fake URL) so no new hotspots remain to review; all other gate conditions already passed. Also address claude-review round 6: - Stale test docstring: "suppresses to ocr" -> "suppresses to the cheapest registered OCR rung (here ocr-upstream)". - OcrProcessor.__init__: comment that the upstream-shaped defaults are test/bare-construction convenience only; app wiring always passes args explicitly. Left as-is (reviewer agreed): the `ocric=` signature abbreviation (opaque but stable; renaming would invalidate dead-letter retries). 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
d05cbc0dc1
commit
985fd5e8f2
@@ -307,6 +307,10 @@ class OcrProcessor(DocumentProcessor):
|
|||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
|
# The defaults describe the UPSTREAM (tier3) rung and exist for
|
||||||
|
# test/bare-construction convenience only. Application wiring
|
||||||
|
# (document_processors/__init__.py) ALWAYS passes every arg explicitly for
|
||||||
|
# both rungs — don't rely on these defaults in app code.
|
||||||
*,
|
*,
|
||||||
name: str = "ocr-upstream",
|
name: str = "ocr-upstream",
|
||||||
tier: str = "ocr-upstream",
|
tier: str = "ocr-upstream",
|
||||||
|
|||||||
@@ -57,7 +57,7 @@ def test_build_backend_none():
|
|||||||
|
|
||||||
def test_build_backend_gateway():
|
def test_build_backend_gateway():
|
||||||
b = ocr.build_ocr_backend(
|
b = ocr.build_ocr_backend(
|
||||||
_settings(document_ocr_provider="gateway", embedding_gateway_url="http://gw")
|
_settings(document_ocr_provider="gateway", embedding_gateway_url="https://gw")
|
||||||
)
|
)
|
||||||
assert isinstance(b, ocr._GatewayOcrBackend)
|
assert isinstance(b, ocr._GatewayOcrBackend)
|
||||||
|
|
||||||
@@ -71,7 +71,7 @@ def test_build_backend_mistral():
|
|||||||
|
|
||||||
def test_build_backend_auto_prefers_gateway():
|
def test_build_backend_auto_prefers_gateway():
|
||||||
b = ocr.build_ocr_backend(
|
b = ocr.build_ocr_backend(
|
||||||
_settings(embedding_gateway_url="http://gw", mistral_api_key="k")
|
_settings(embedding_gateway_url="https://gw", mistral_api_key="k")
|
||||||
)
|
)
|
||||||
assert isinstance(b, ocr._GatewayOcrBackend)
|
assert isinstance(b, ocr._GatewayOcrBackend)
|
||||||
|
|
||||||
@@ -111,7 +111,7 @@ def test_build_backend_gateway_only_forces_gateway():
|
|||||||
_settings(
|
_settings(
|
||||||
document_ocr_provider="mistral",
|
document_ocr_provider="mistral",
|
||||||
mistral_api_key="k",
|
mistral_api_key="k",
|
||||||
embedding_gateway_url="http://gw",
|
embedding_gateway_url="https://gw",
|
||||||
),
|
),
|
||||||
gateway_only=True,
|
gateway_only=True,
|
||||||
)
|
)
|
||||||
@@ -135,7 +135,7 @@ def test_build_backend_gateway_only_provider_none_warns_when_incluster_enabled(c
|
|||||||
b = ocr.build_ocr_backend(
|
b = ocr.build_ocr_backend(
|
||||||
_settings(
|
_settings(
|
||||||
document_ocr_provider="none",
|
document_ocr_provider="none",
|
||||||
embedding_gateway_url="http://gw",
|
embedding_gateway_url="https://gw",
|
||||||
document_ocr_incluster_enabled=True,
|
document_ocr_incluster_enabled=True,
|
||||||
),
|
),
|
||||||
gateway_only=True,
|
gateway_only=True,
|
||||||
@@ -155,7 +155,7 @@ def test_build_backend_gateway_only_provider_none_silent_when_incluster_disabled
|
|||||||
"WARNING", logger="nextcloud_mcp_server.document_processors.ocr"
|
"WARNING", logger="nextcloud_mcp_server.document_processors.ocr"
|
||||||
):
|
):
|
||||||
b = ocr.build_ocr_backend(
|
b = ocr.build_ocr_backend(
|
||||||
_settings(document_ocr_provider="none", embedding_gateway_url="http://gw"),
|
_settings(document_ocr_provider="none", embedding_gateway_url="https://gw"),
|
||||||
gateway_only=True,
|
gateway_only=True,
|
||||||
)
|
)
|
||||||
assert b is None
|
assert b is None
|
||||||
@@ -166,7 +166,7 @@ def test_build_backend_empty_model_does_not_fall_back(caplog):
|
|||||||
"""An empty model string must NOT silently fall back to the upstream default
|
"""An empty model string must NOT silently fall back to the upstream default
|
||||||
(an `or` would); the in-cluster rung keeps the empty id it was handed."""
|
(an `or` would); the in-cluster rung keeps the empty id it was handed."""
|
||||||
b = ocr.build_ocr_backend(
|
b = ocr.build_ocr_backend(
|
||||||
_settings(embedding_gateway_url="http://gw"),
|
_settings(embedding_gateway_url="https://gw"),
|
||||||
model="",
|
model="",
|
||||||
gateway_only=True,
|
gateway_only=True,
|
||||||
)
|
)
|
||||||
@@ -178,14 +178,14 @@ def test_build_backend_model_override_is_not_hardcoded():
|
|||||||
"""The per-tier model is whatever config passes -- surya by default, but fully
|
"""The per-tier model is whatever config passes -- surya by default, but fully
|
||||||
swappable (e.g. lightonocr) with no code change."""
|
swappable (e.g. lightonocr) with no code change."""
|
||||||
surya = ocr.build_ocr_backend(
|
surya = ocr.build_ocr_backend(
|
||||||
_settings(embedding_gateway_url="http://gw"),
|
_settings(embedding_gateway_url="https://gw"),
|
||||||
model="surya/surya-ocr-2",
|
model="surya/surya-ocr-2",
|
||||||
gateway_only=True,
|
gateway_only=True,
|
||||||
)
|
)
|
||||||
assert isinstance(surya, ocr._GatewayOcrBackend)
|
assert isinstance(surya, ocr._GatewayOcrBackend)
|
||||||
assert surya._model == "surya/surya-ocr-2"
|
assert surya._model == "surya/surya-ocr-2"
|
||||||
lit = ocr.build_ocr_backend(
|
lit = ocr.build_ocr_backend(
|
||||||
_settings(embedding_gateway_url="http://gw"),
|
_settings(embedding_gateway_url="https://gw"),
|
||||||
model="lightonocr/lightonocr-1b",
|
model="lightonocr/lightonocr-1b",
|
||||||
gateway_only=True,
|
gateway_only=True,
|
||||||
)
|
)
|
||||||
@@ -213,7 +213,7 @@ async def test_incluster_processor_resolves_its_model_gateway_only(monkeypatch):
|
|||||||
"get_settings",
|
"get_settings",
|
||||||
lambda: _settings(
|
lambda: _settings(
|
||||||
document_ocr_incluster_model="surya/surya-ocr-2",
|
document_ocr_incluster_model="surya/surya-ocr-2",
|
||||||
embedding_gateway_url="http://gw",
|
embedding_gateway_url="https://gw",
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
proc = ocr.OcrProcessor(
|
proc = ocr.OcrProcessor(
|
||||||
@@ -250,17 +250,17 @@ def test_build_backend_gateway_missing_m2m_raises():
|
|||||||
ocr.build_ocr_backend(
|
ocr.build_ocr_backend(
|
||||||
_settings(
|
_settings(
|
||||||
document_ocr_provider="gateway",
|
document_ocr_provider="gateway",
|
||||||
embedding_gateway_url="http://gw",
|
embedding_gateway_url="https://gw",
|
||||||
embedding_gateway_client_id="cid",
|
embedding_gateway_client_id="cid",
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def test_gateway_backend_url_normalization():
|
def test_gateway_backend_url_normalization():
|
||||||
b = ocr._GatewayOcrBackend("http://gw", "mistral/mistral-ocr-latest")
|
b = ocr._GatewayOcrBackend("https://gw", "mistral/mistral-ocr-latest")
|
||||||
assert b._url == "http://gw/v1/ocr"
|
assert b._url == "https://gw/v1/ocr"
|
||||||
b2 = ocr._GatewayOcrBackend("http://gw/v1/", "m")
|
b2 = ocr._GatewayOcrBackend("https://gw/v1/", "m")
|
||||||
assert b2._url == "http://gw/v1/ocr"
|
assert b2._url == "https://gw/v1/ocr"
|
||||||
|
|
||||||
|
|
||||||
# --- OcrProcessor ------------------------------------------------------------
|
# --- OcrProcessor ------------------------------------------------------------
|
||||||
|
|||||||
@@ -751,9 +751,10 @@ def test_evaluate_escalation_terminal_when_ocr_unregistered_and_off(monkeypatch)
|
|||||||
def test_evaluate_escalation_empty_suppressed_even_when_structured_registered(
|
def test_evaluate_escalation_empty_suppressed_even_when_structured_registered(
|
||||||
monkeypatch,
|
monkeypatch,
|
||||||
):
|
):
|
||||||
"""empty_text uses minimum='ocr-incluster', so it skips structured even when structured
|
"""empty_text uses minimum='ocr-incluster', so it skips structured even when
|
||||||
IS registered: with OCR off it suppresses to ocr, never hops to structured
|
structured IS registered: with OCR off it suppresses to the cheapest registered
|
||||||
(a text extractor can't conjure text from a raster scan)."""
|
OCR rung (here ocr-upstream, the only one registered in this test), never hops
|
||||||
|
to structured (a text extractor can't conjure text from a raster scan)."""
|
||||||
monkeypatch.setattr(reg_mod, "record_document_classification", MagicMock())
|
monkeypatch.setattr(reg_mod, "record_document_classification", MagicMock())
|
||||||
r = _registry(
|
r = _registry(
|
||||||
(_Fake("fast", "fast"), 20),
|
(_Fake("fast", "fast"), 20),
|
||||||
|
|||||||
Reference in New Issue
Block a user