These files were not touched by the recent performance and correctness PRs but had coverage gaps. Adds tests for: - CLI: serve, queue init/migrate, config loading, cli() entry point including MigrationRequiredError exit path - filter: _default_supported_extensions, __call__ watchfiles callback, FileFilter with supported_extensions=None - registry: resolve_adhoc_fetcher with bucket-less S3 URI - migrations: pragma no-cover on unreachable schema upgrade path (no diff migrations exist until SCHEMA_VERSION > 1)
165 lines
4.7 KiB
Python
165 lines
4.7 KiB
Python
"""haiku-ingester CLI: exercises every subcommand via CliRunner with
|
|
IngesterApp / open_queue patched out so no real ingestion runs."""
|
|
|
|
from unittest.mock import AsyncMock, MagicMock
|
|
|
|
import pytest
|
|
from typer.testing import CliRunner
|
|
|
|
from haiku.rag.ingester.app import BatchReport
|
|
from haiku.rag.ingester.cli import _cli as cli
|
|
|
|
runner = CliRunner()
|
|
|
|
|
|
# --- helpers ---
|
|
|
|
|
|
def _fake_app(report: BatchReport, monkeypatch) -> AsyncMock:
|
|
fake = AsyncMock()
|
|
fake.run_batch.return_value = report
|
|
monkeypatch.setattr("haiku.rag.ingester.cli.IngesterApp", lambda **_: fake)
|
|
return fake
|
|
|
|
|
|
def test_run_batch_reports_and_exits_zero(monkeypatch):
|
|
fake = _fake_app(BatchReport(succeeded=3, dead=0), monkeypatch)
|
|
|
|
result = runner.invoke(cli, ["run-batch", "--db", "x.lancedb"])
|
|
|
|
assert result.exit_code == 0
|
|
assert "3 succeeded, 0 dead" in result.output
|
|
fake.run_batch.assert_awaited_once()
|
|
|
|
|
|
def test_run_batch_exits_nonzero_when_dead(monkeypatch):
|
|
_fake_app(BatchReport(succeeded=1, dead=2), monkeypatch)
|
|
|
|
result = runner.invoke(cli, ["run-batch", "--db", "x.lancedb"])
|
|
|
|
assert result.exit_code == 1
|
|
assert "2 dead" in result.output
|
|
|
|
|
|
def test_run_batch_exits_nonzero_when_sweep_fails(monkeypatch):
|
|
_fake_app(BatchReport(succeeded=2, dead=0, failed_sweeps=["docs"]), monkeypatch)
|
|
|
|
result = runner.invoke(cli, ["run-batch", "--db", "x.lancedb"])
|
|
|
|
assert result.exit_code == 1
|
|
assert "failed to sweep: docs" in result.output
|
|
|
|
|
|
# --- serve ---
|
|
|
|
|
|
def test_serve_invokes_app(monkeypatch):
|
|
fake = AsyncMock()
|
|
monkeypatch.setattr("haiku.rag.ingester.cli.IngesterApp", lambda **_: fake)
|
|
|
|
result = runner.invoke(cli, ["serve", "--db", "x.lancedb", "--no-api"])
|
|
|
|
assert result.exit_code == 0
|
|
fake.serve.assert_awaited_once_with(api=False)
|
|
|
|
|
|
def test_serve_passes_host_and_port(monkeypatch):
|
|
fake = AsyncMock()
|
|
captured = {}
|
|
|
|
def _capture(**kwargs):
|
|
captured.update(kwargs)
|
|
return fake
|
|
|
|
monkeypatch.setattr("haiku.rag.ingester.cli.IngesterApp", _capture)
|
|
|
|
result = runner.invoke(
|
|
cli, ["serve", "--db", "x.lancedb", "--host", "0.0.0.0", "--port", "9999"]
|
|
)
|
|
|
|
assert result.exit_code == 0
|
|
assert captured["config"].ingester.api.host == "0.0.0.0"
|
|
assert captured["config"].ingester.api.port == 9999
|
|
|
|
|
|
# --- queue init / migrate ---
|
|
|
|
|
|
def test_queue_init(tmp_path, monkeypatch):
|
|
fake_conn = AsyncMock()
|
|
monkeypatch.setattr(
|
|
"haiku.rag.ingester.cli.open_queue", AsyncMock(return_value=fake_conn)
|
|
)
|
|
|
|
db_path = tmp_path / "queue.db"
|
|
result = runner.invoke(cli, ["queue", "init", "--queue", str(db_path)])
|
|
|
|
assert result.exit_code == 0
|
|
assert "initialized" in result.output
|
|
|
|
|
|
def test_queue_migrate(tmp_path, monkeypatch):
|
|
fake_conn = AsyncMock()
|
|
monkeypatch.setattr(
|
|
"haiku.rag.ingester.cli.open_queue", AsyncMock(return_value=fake_conn)
|
|
)
|
|
|
|
db_path = tmp_path / "queue.db"
|
|
result = runner.invoke(cli, ["queue", "migrate", "--queue", str(db_path)])
|
|
|
|
assert result.exit_code == 0
|
|
assert "up to date" in result.output
|
|
|
|
|
|
# --- config loading ---
|
|
|
|
|
|
def test_load_config_with_explicit_path(tmp_path):
|
|
from haiku.rag.ingester.cli import _load_config_with_override
|
|
|
|
config_file = tmp_path / "test.yaml"
|
|
config_file.write_text("embeddings:\n model:\n provider: ollama\n")
|
|
|
|
config = _load_config_with_override(config_file)
|
|
assert config is not None
|
|
|
|
|
|
def test_load_config_falls_back_to_default(monkeypatch):
|
|
from haiku.rag.ingester.cli import _load_config_with_override
|
|
|
|
monkeypatch.setattr("haiku.rag.ingester.cli.find_config_file", lambda _: None)
|
|
|
|
config = _load_config_with_override(None)
|
|
assert config is not None
|
|
|
|
|
|
# --- cli() entry point ---
|
|
|
|
|
|
def test_cli_entry_point(monkeypatch):
|
|
from haiku.rag.ingester.cli import cli as cli_entry
|
|
|
|
mock_cli = MagicMock()
|
|
monkeypatch.setattr("haiku.rag.ingester.cli._cli", mock_cli)
|
|
monkeypatch.setattr("haiku.rag.ingester.cli.configure_cli_logging", lambda: None)
|
|
monkeypatch.setattr("haiku.rag.telemetry.configure", lambda **_: None)
|
|
|
|
cli_entry()
|
|
|
|
mock_cli.assert_called_once()
|
|
|
|
|
|
def test_cli_entry_point_exits_on_migration_error(monkeypatch):
|
|
from haiku.rag.ingester.cli import cli as cli_entry
|
|
from haiku.rag.store.exceptions import MigrationRequiredError
|
|
|
|
monkeypatch.setattr(
|
|
"haiku.rag.ingester.cli._cli",
|
|
MagicMock(side_effect=MigrationRequiredError("need migration")),
|
|
)
|
|
monkeypatch.setattr("haiku.rag.ingester.cli.configure_cli_logging", lambda: None)
|
|
monkeypatch.setattr("haiku.rag.telemetry.configure", lambda **_: None)
|
|
|
|
with pytest.raises(SystemExit) as exc_info:
|
|
cli_entry()
|
|
assert exc_info.value.code == 1
|