Add tests for migration scenarios
This commit is contained in:
parent
8b2cc19288
commit
f582552f6a
2 changed files with 133 additions and 0 deletions
|
|
@ -602,3 +602,74 @@ async def test_rebuild_empty_database(tmp_path, monkeypatch):
|
||||||
|
|
||||||
calls = [str(c) for c in mock_print.call_args_list]
|
calls = [str(c) for c in mock_print.call_args_list]
|
||||||
assert any("No documents found" in c for c in calls)
|
assert any("No documents found" in c for c in calls)
|
||||||
|
|
||||||
|
|
||||||
|
def test_migrate_with_pending_migrations(tmp_path):
|
||||||
|
"""Test migrate method when migrations are applied."""
|
||||||
|
from haiku.rag.store.engine import Store
|
||||||
|
|
||||||
|
db_path = tmp_path / "test.lancedb"
|
||||||
|
store = Store(db_path, create=True)
|
||||||
|
store.close()
|
||||||
|
|
||||||
|
app = HaikuRAGApp(db_path=db_path)
|
||||||
|
|
||||||
|
with patch("haiku.rag.store.engine.Store") as mock_store_class:
|
||||||
|
mock_store = MagicMock()
|
||||||
|
mock_store.migrate.return_value = ["Migration 1", "Migration 2"]
|
||||||
|
mock_store_class.return_value = mock_store
|
||||||
|
|
||||||
|
result = app.migrate()
|
||||||
|
|
||||||
|
mock_store_class.assert_called_once_with(
|
||||||
|
db_path,
|
||||||
|
config=app.config,
|
||||||
|
skip_validation=True,
|
||||||
|
skip_migration_check=True,
|
||||||
|
)
|
||||||
|
mock_store.migrate.assert_called_once()
|
||||||
|
mock_store.close.assert_called_once()
|
||||||
|
assert result == ["Migration 1", "Migration 2"]
|
||||||
|
|
||||||
|
|
||||||
|
def test_migrate_no_pending_migrations(tmp_path):
|
||||||
|
"""Test migrate method when no migrations are pending."""
|
||||||
|
from haiku.rag.store.engine import Store
|
||||||
|
|
||||||
|
db_path = tmp_path / "test.lancedb"
|
||||||
|
store = Store(db_path, create=True)
|
||||||
|
store.close()
|
||||||
|
|
||||||
|
app = HaikuRAGApp(db_path=db_path)
|
||||||
|
|
||||||
|
with patch("haiku.rag.store.engine.Store") as mock_store_class:
|
||||||
|
mock_store = MagicMock()
|
||||||
|
mock_store.migrate.return_value = []
|
||||||
|
mock_store_class.return_value = mock_store
|
||||||
|
|
||||||
|
result = app.migrate()
|
||||||
|
|
||||||
|
mock_store.migrate.assert_called_once()
|
||||||
|
mock_store.close.assert_called_once()
|
||||||
|
assert result == []
|
||||||
|
|
||||||
|
|
||||||
|
def test_migrate_closes_store_on_exception(tmp_path):
|
||||||
|
"""Test migrate method closes store even if migration fails."""
|
||||||
|
from haiku.rag.store.engine import Store
|
||||||
|
|
||||||
|
db_path = tmp_path / "test.lancedb"
|
||||||
|
store = Store(db_path, create=True)
|
||||||
|
store.close()
|
||||||
|
|
||||||
|
app = HaikuRAGApp(db_path=db_path)
|
||||||
|
|
||||||
|
with patch("haiku.rag.store.engine.Store") as mock_store_class:
|
||||||
|
mock_store = MagicMock()
|
||||||
|
mock_store.migrate.side_effect = Exception("Migration error")
|
||||||
|
mock_store_class.return_value = mock_store
|
||||||
|
|
||||||
|
with pytest.raises(Exception, match="Migration error"):
|
||||||
|
app.migrate()
|
||||||
|
|
||||||
|
mock_store.close.assert_called_once()
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,8 @@ from unittest.mock import AsyncMock, MagicMock, patch
|
||||||
from typer.testing import CliRunner
|
from typer.testing import CliRunner
|
||||||
|
|
||||||
from haiku.rag.cli import _cli as cli
|
from haiku.rag.cli import _cli as cli
|
||||||
|
from haiku.rag.cli import cli as cli_wrapper
|
||||||
|
from haiku.rag.store.exceptions import MigrationRequiredError
|
||||||
|
|
||||||
runner = CliRunner()
|
runner = CliRunner()
|
||||||
|
|
||||||
|
|
@ -386,3 +388,63 @@ def test_add_document_src_directory(tmp_path):
|
||||||
mock_app_instance.add_document_from_source.assert_called_once()
|
mock_app_instance.add_document_from_source.assert_called_once()
|
||||||
call_args = mock_app_instance.add_document_from_source.call_args
|
call_args = mock_app_instance.add_document_from_source.call_args
|
||||||
assert call_args[1]["source"] == str(test_dir)
|
assert call_args[1]["source"] == str(test_dir)
|
||||||
|
|
||||||
|
|
||||||
|
def test_migrate_with_applied_migrations():
|
||||||
|
"""Test migrate command when migrations are applied."""
|
||||||
|
with patch("haiku.rag.cli.HaikuRAGApp") as mock_app:
|
||||||
|
mock_app_instance = MagicMock()
|
||||||
|
mock_app_instance.migrate.return_value = [
|
||||||
|
"Add full-text search index",
|
||||||
|
"Add metadata column",
|
||||||
|
]
|
||||||
|
mock_app.return_value = mock_app_instance
|
||||||
|
|
||||||
|
result = runner.invoke(cli, ["migrate"])
|
||||||
|
|
||||||
|
assert result.exit_code == 0
|
||||||
|
mock_app_instance.migrate.assert_called_once()
|
||||||
|
assert "Applied 2 migration(s)" in result.output
|
||||||
|
assert "Add full-text search index" in result.output
|
||||||
|
assert "Add metadata column" in result.output
|
||||||
|
assert "Migration completed successfully" in result.output
|
||||||
|
|
||||||
|
|
||||||
|
def test_migrate_no_pending_migrations():
|
||||||
|
"""Test migrate command when no migrations are pending."""
|
||||||
|
with patch("haiku.rag.cli.HaikuRAGApp") as mock_app:
|
||||||
|
mock_app_instance = MagicMock()
|
||||||
|
mock_app_instance.migrate.return_value = []
|
||||||
|
mock_app.return_value = mock_app_instance
|
||||||
|
|
||||||
|
result = runner.invoke(cli, ["migrate"])
|
||||||
|
|
||||||
|
assert result.exit_code == 0
|
||||||
|
mock_app_instance.migrate.assert_called_once()
|
||||||
|
assert "No migrations pending" in result.output
|
||||||
|
assert "Database is up to date" in result.output
|
||||||
|
|
||||||
|
|
||||||
|
def test_migrate_failure():
|
||||||
|
"""Test migrate command when migration fails."""
|
||||||
|
with patch("haiku.rag.cli.HaikuRAGApp") as mock_app:
|
||||||
|
mock_app_instance = MagicMock()
|
||||||
|
mock_app_instance.migrate.side_effect = Exception("Migration failed")
|
||||||
|
mock_app.return_value = mock_app_instance
|
||||||
|
|
||||||
|
result = runner.invoke(cli, ["migrate"])
|
||||||
|
|
||||||
|
assert result.exit_code == 1
|
||||||
|
assert "Migration failed" in result.output
|
||||||
|
|
||||||
|
|
||||||
|
def test_cli_wrapper_catches_migration_required_error():
|
||||||
|
"""Test that cli() wrapper catches MigrationRequiredError and exits with code 1."""
|
||||||
|
with patch("haiku.rag.cli._cli") as mock_cli:
|
||||||
|
mock_cli.side_effect = MigrationRequiredError(
|
||||||
|
"Database requires migration. Run 'haiku-rag migrate' to upgrade."
|
||||||
|
)
|
||||||
|
|
||||||
|
with patch("sys.exit") as mock_exit:
|
||||||
|
cli_wrapper()
|
||||||
|
mock_exit.assert_called_once_with(1)
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue