mirror of
https://github.com/lfnovo/open-notebook.git
synced 2026-08-04 21:33:51 +00:00
Some checks are pending
Development Build / extract-version (push) Waiting to run
Development Build / changes (push) Waiting to run
Tests / Frontend Lint (push) Waiting to run
Tests / Backend Tests (push) Waiting to run
Tests / Backend Lint (push) Waiting to run
Tests / Backend Typecheck (push) Waiting to run
Development Build / build-regular (push) Blocked by required conditions
Development Build / build-single (push) Blocked by required conditions
Development Build / summary (push) Blocked by required conditions
Tests / Frontend Tests (push) Waiting to run
Tests / Frontend Build (push) Waiting to run
* fix(sources): fall back to auto when a selected engine's runtime is absent The content-processing engine choice is persisted in the database; the runtime that serves it (Docling, local Crawl4AI) is installed on demand from environment flags evaluated at boot. The two therefore drift: a redeploy that drops OPEN_NOTEBOOK_ENABLE_CRAWL4AI/_DOCLING, a volume moved to a new deployment, or a failed on-demand install all leave a stored selection pointing at a runtime that is not there. The source graph passed that selection straight to content-core, so every affected extraction failed with "Could not extract any text content from this source" - no mention of the engine, the runtime, or the flag that would fix it. For a URL engine set to crawl4ai this breaks URL ingestion entirely. The graph now checks runtime availability before honoring the stored engine and degrades to content-core's "auto" chain, logging a WARNING that names the engine and the env var that would enable it. Engines with no opt-in runtime (auto/simple/firecrawl/jina) are passed through untouched. The availability probes moved from api/routers/capabilities.py to open_notebook/utils/runtime_capabilities.py so the graph can use them without importing from the API layer; the capabilities endpoint keeps identical behavior and its tests follow the probes to their new home. Found by the smoke-e2e agent during v1.14.0 release testing, on a dev environment that was in exactly this state. Pre-existing since v1.13.0 (#1122 made the runtimes opt-in, #432 made the stored selection take effect), not a v1.14.0 regression. * docs(changelog): record the unavailable-engine fallback fix
78 lines
3 KiB
Python
78 lines
3 KiB
Python
"""Tests for the opt-in runtime availability probes.
|
|
|
|
The engine choice lives in the database; the runtime that serves it comes from
|
|
environment flags evaluated at boot. engine_runtime_missing() is what keeps the
|
|
two from drifting into a state where extraction is routed to a runtime that
|
|
isn't installed.
|
|
"""
|
|
|
|
from unittest.mock import patch
|
|
|
|
from open_notebook.utils.runtime_capabilities import engine_runtime_missing
|
|
|
|
|
|
class TestEngineRuntimeMissing:
|
|
def test_runtime_free_engines_need_nothing(self):
|
|
"""auto/simple/firecrawl/jina carry no opt-in runtime."""
|
|
for engine in ("auto", "simple", "firecrawl", "jina"):
|
|
assert engine_runtime_missing(engine) is None
|
|
|
|
def test_none_and_empty_are_not_missing(self):
|
|
assert engine_runtime_missing(None) is None
|
|
assert engine_runtime_missing("") is None
|
|
|
|
def test_unknown_engine_is_passed_through(self):
|
|
"""An engine we don't know about is content-core's problem, not ours."""
|
|
assert engine_runtime_missing("some-future-engine") is None
|
|
|
|
def test_crawl4ai_reports_its_env_var_when_absent(self):
|
|
with patch(
|
|
"open_notebook.utils.runtime_capabilities.crawl4ai_available",
|
|
return_value=False,
|
|
):
|
|
assert (
|
|
engine_runtime_missing("crawl4ai") == "OPEN_NOTEBOOK_ENABLE_CRAWL4AI"
|
|
)
|
|
|
|
def test_crawl4ai_is_usable_when_available(self):
|
|
with patch(
|
|
"open_notebook.utils.runtime_capabilities.crawl4ai_available",
|
|
return_value=True,
|
|
):
|
|
assert engine_runtime_missing("crawl4ai") is None
|
|
|
|
def test_docling_reports_its_env_var_when_absent(self):
|
|
with patch(
|
|
"open_notebook.utils.runtime_capabilities.docling_available",
|
|
return_value=False,
|
|
):
|
|
assert engine_runtime_missing("docling") == "OPEN_NOTEBOOK_ENABLE_DOCLING"
|
|
|
|
def test_docling_is_usable_when_available(self):
|
|
with patch(
|
|
"open_notebook.utils.runtime_capabilities.docling_available",
|
|
return_value=True,
|
|
):
|
|
assert engine_runtime_missing("docling") is None
|
|
|
|
def test_engine_name_is_normalized(self):
|
|
"""Stored values shouldn't have to be exactly lowercased to be gated."""
|
|
with patch(
|
|
"open_notebook.utils.runtime_capabilities.crawl4ai_available",
|
|
return_value=False,
|
|
):
|
|
assert (
|
|
engine_runtime_missing(" Crawl4AI ")
|
|
== "OPEN_NOTEBOOK_ENABLE_CRAWL4AI"
|
|
)
|
|
|
|
def test_remote_crawl4ai_counts_as_available(self):
|
|
"""CRAWL4AI_API_URL offloads rendering — no local install needed."""
|
|
with patch(
|
|
"open_notebook.utils.runtime_capabilities.crawl4ai_local_ready",
|
|
return_value=False,
|
|
), patch(
|
|
"open_notebook.utils.runtime_capabilities.crawl4ai_remote_configured",
|
|
return_value=True,
|
|
):
|
|
assert engine_runtime_missing("crawl4ai") is None
|