Files
wehub-resource-sync e4dcfc49aa
Tests / Lint and Format (push) Waiting to run
Tests / Web Node Tests (push) Waiting to run
Tests / Import Check (Python 3.11) (push) Waiting to run
Tests / Import Check (Python 3.12) (push) Waiting to run
Tests / Import Check (Python 3.13) (push) Waiting to run
Tests / Import Check (Python 3.14) (push) Waiting to run
Tests / Python Tests (Python 3.11) (push) Blocked by required conditions
Tests / Python Tests (Python 3.12) (push) Blocked by required conditions
Tests / Python Tests (Python 3.13) (push) Blocked by required conditions
Tests / Python Tests (Python 3.14) (push) Blocked by required conditions
Tests / Test Summary (push) Blocked by required conditions
chore: import upstream snapshot with attribution
2026-07-13 13:00:43 +08:00

176 lines
5.8 KiB
Python

from __future__ import annotations
from pathlib import Path
import threading
import time
import pytest
from deeptutor.services.parsing.engines.mineru import models as mineru_models
from deeptutor.services.parsing.engines.mineru.models import (
ModelDownloadManager,
model_env_overrides,
resolve_models_downloader,
)
# ---------------------------------------------------------------------------
# Downloader resolution
# ---------------------------------------------------------------------------
def test_resolver_prefers_configured_cli_sibling(tmp_path: Path) -> None:
bin_dir = tmp_path / "env" / "bin"
bin_dir.mkdir(parents=True)
cli = bin_dir / "mineru"
cli.write_text("#!/bin/sh\n", encoding="utf-8")
cli.chmod(0o755)
downloader = bin_dir / "mineru-models-download"
downloader.write_text("#!/bin/sh\n", encoding="utf-8")
downloader.chmod(0o755)
resolved = resolve_models_downloader(str(cli))
assert resolved == {"found": True, "path": str(downloader)}
def test_resolver_reports_missing_sibling_no_path_fallback(
tmp_path: Path, monkeypatch: pytest.MonkeyPatch
) -> None:
# Even if PATH has the downloader, a configured CLI without a sibling
# downloader is a miss — the configured env is authoritative.
monkeypatch.setattr(
mineru_models.shutil, "which", lambda cmd: "/usr/bin/mineru-models-download"
)
cli = tmp_path / "mineru"
cli.write_text("#!/bin/sh\n", encoding="utf-8")
cli.chmod(0o755)
resolved = resolve_models_downloader(str(cli))
assert resolved["found"] is False
assert resolved["path"].endswith("mineru-models-download")
def test_resolver_falls_back_to_path(monkeypatch: pytest.MonkeyPatch) -> None:
monkeypatch.setattr(
mineru_models.shutil, "which", lambda cmd: "/opt/bin/mineru-models-download"
)
assert resolve_models_downloader("") == {
"found": True,
"path": "/opt/bin/mineru-models-download",
}
monkeypatch.setattr(mineru_models.shutil, "which", lambda cmd: None)
assert resolve_models_downloader("")["found"] is False
# ---------------------------------------------------------------------------
# Env overrides
# ---------------------------------------------------------------------------
def test_model_env_overrides_shapes() -> None:
assert model_env_overrides("huggingface") == {"MINERU_MODEL_SOURCE": "huggingface"}
assert model_env_overrides("huggingface", "https://hf-mirror.com/") == {
"MINERU_MODEL_SOURCE": "huggingface",
"HF_ENDPOINT": "https://hf-mirror.com",
}
# Endpoint is an HF-only concept; modelscope ignores it.
assert model_env_overrides("modelscope", "https://hf-mirror.com") == {
"MINERU_MODEL_SOURCE": "modelscope"
}
# Unknown source degrades to the default.
assert model_env_overrides("weird")["MINERU_MODEL_SOURCE"] == "huggingface"
# ---------------------------------------------------------------------------
# Download job manager
# ---------------------------------------------------------------------------
class _FakeProc:
def __init__(self, lines, returncode: int = 0):
self.stdout = iter(lines)
self._returncode = returncode
self.terminated = False
def wait(self) -> int:
return -15 if self.terminated else self._returncode
def poll(self):
return None if not self.terminated else -15
def terminate(self) -> None:
self.terminated = True
def _wait_for_terminal(manager: ModelDownloadManager, timeout: float = 2.0) -> str:
deadline = time.monotonic() + timeout
while time.monotonic() < deadline:
state = manager.status()["state"]
if state != "running":
return state
time.sleep(0.01)
return manager.status()["state"]
def test_manager_happy_path_and_cursor(monkeypatch: pytest.MonkeyPatch) -> None:
manager = ModelDownloadManager()
monkeypatch.setattr(
mineru_models.subprocess,
"Popen",
lambda *a, **k: _FakeProc(["downloading layout model...\n"]),
)
result = manager.start(
downloader="/x/mineru-models-download",
model_type="pipeline",
source="huggingface",
)
assert result["ok"] is True
assert _wait_for_terminal(manager) == "done"
status = manager.status(0)
assert status["lines"] == ["downloading layout model..."]
assert status["message"] == "Download finished."
# Cursor protocol: re-polling from next_cursor yields nothing new.
assert manager.status(status["next_cursor"])["lines"] == []
def test_manager_nonzero_exit_is_failed(monkeypatch: pytest.MonkeyPatch) -> None:
manager = ModelDownloadManager()
monkeypatch.setattr(
mineru_models.subprocess,
"Popen",
lambda *a, **k: _FakeProc(["boom\n"], returncode=3),
)
assert manager.start(downloader="/x/dl", model_type="pipeline", source="huggingface")["ok"]
assert _wait_for_terminal(manager) == "failed"
assert "code 3" in manager.status()["message"]
def test_manager_rejects_concurrent_start_and_cancels(
monkeypatch: pytest.MonkeyPatch,
) -> None:
release = threading.Event()
def blocking_lines():
yield "starting\n"
release.wait(timeout=5)
proc = _FakeProc(blocking_lines())
monkeypatch.setattr(mineru_models.subprocess, "Popen", lambda *a, **k: proc)
manager = ModelDownloadManager()
assert manager.start(downloader="/x/dl", model_type="all", source="modelscope")["ok"]
# Busy: a second start is rejected while the first is running.
busy = manager.start(downloader="/x/dl", model_type="pipeline", source="huggingface")
assert busy["ok"] is False
cancelled = manager.cancel()
assert cancelled["ok"] is True
release.set()
assert _wait_for_terminal(manager) == "cancelled"
def test_manager_cancel_without_job() -> None:
assert ModelDownloadManager().cancel()["ok"] is False