Skip to content

Commit 516c78a

Browse files
test: add comprehensive tests for db reset command
- Test that reset command clears project configuration to defaults - Test user cancellation behavior - Test --reindex flag functionality - Test handling of non-existent database files - Follow existing test patterns and proper mocking Co-authored-by: Paul Hernandez <phernandez@users.noreply.github.com>
1 parent 01fb089 commit 516c78a

1 file changed

Lines changed: 128 additions & 0 deletions

File tree

tests/cli/test_db_commands.py

Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
"""Tests for database CLI commands."""
2+
3+
from pathlib import Path
4+
from unittest.mock import patch, AsyncMock, MagicMock
5+
6+
from typer.testing import CliRunner
7+
8+
from basic_memory.cli.main import app as cli_app
9+
10+
11+
def test_reset_command_clears_project_configuration(config_manager, app_config):
12+
"""Test that the reset command clears project configuration to defaults."""
13+
runner = CliRunner()
14+
15+
# Set up initial configuration with multiple projects
16+
config_manager.config.projects = {
17+
"project1": "/path/to/project1",
18+
"project2": "/path/to/project2",
19+
"test-project": "/path/to/test"
20+
}
21+
config_manager.config.default_project = "project1"
22+
23+
# Mock the confirmation to return True (user confirms reset)
24+
with patch("basic_memory.cli.commands.db.typer.confirm", return_value=True):
25+
# Mock the database file existence check and deletion
26+
with patch("pathlib.Path.exists", return_value=True):
27+
with patch("pathlib.Path.unlink") as mock_unlink:
28+
# Mock the async db.run_migrations function
29+
with patch("basic_memory.cli.commands.db.asyncio.run") as mock_run:
30+
mock_run.return_value = None
31+
32+
# Run the reset command
33+
result = runner.invoke(cli_app, ["db", "reset"])
34+
35+
# Should exit successfully
36+
assert result.exit_code == 0
37+
38+
# Database file should be deleted
39+
mock_unlink.assert_called_once()
40+
41+
# Async migrations should be called
42+
mock_run.assert_called_once()
43+
44+
# Configuration should be reset to defaults
45+
expected_projects = {"main": str(Path.home() / "basic-memory")}
46+
assert config_manager.config.projects == expected_projects
47+
assert config_manager.config.default_project == "main"
48+
49+
50+
def test_reset_command_user_cancels(config_manager):
51+
"""Test that the reset command does nothing when user cancels."""
52+
runner = CliRunner()
53+
54+
# Set up initial configuration
55+
original_projects = {
56+
"project1": "/path/to/project1",
57+
"project2": "/path/to/project2"
58+
}
59+
config_manager.config.projects = original_projects.copy()
60+
config_manager.config.default_project = "project1"
61+
62+
# Mock the confirmation to return False (user cancels)
63+
with patch("basic_memory.cli.commands.db.typer.confirm", return_value=False):
64+
with patch("pathlib.Path.unlink") as mock_unlink:
65+
with patch("basic_memory.cli.commands.db.asyncio.run") as mock_run:
66+
# Run the reset command
67+
result = runner.invoke(cli_app, ["db", "reset"])
68+
69+
# Should exit successfully
70+
assert result.exit_code == 0
71+
72+
# No database operations should occur
73+
mock_unlink.assert_not_called()
74+
mock_run.assert_not_called()
75+
76+
# Configuration should remain unchanged
77+
assert config_manager.config.projects == original_projects
78+
assert config_manager.config.default_project == "project1"
79+
80+
81+
def test_reset_command_with_reindex(config_manager):
82+
"""Test that the reset command with --reindex flag calls sync."""
83+
runner = CliRunner()
84+
85+
# Mock the confirmation to return True
86+
with patch("basic_memory.cli.commands.db.typer.confirm", return_value=True):
87+
# Mock database operations
88+
with patch("pathlib.Path.exists", return_value=True):
89+
with patch("pathlib.Path.unlink"):
90+
with patch("basic_memory.cli.commands.db.asyncio.run"):
91+
# Mock the sync command that gets imported and called
92+
with patch("basic_memory.cli.commands.db.sync") as mock_sync:
93+
# Run the reset command with reindex flag
94+
result = runner.invoke(cli_app, ["db", "reset", "--reindex"])
95+
96+
# Should exit successfully
97+
assert result.exit_code == 0
98+
99+
# Sync should be called with watch=False
100+
mock_sync.assert_called_once_with(watch=False)
101+
102+
103+
def test_reset_command_nonexistent_database(config_manager):
104+
"""Test reset command when database file doesn't exist."""
105+
runner = CliRunner()
106+
107+
# Mock the confirmation to return True
108+
with patch("basic_memory.cli.commands.db.typer.confirm", return_value=True):
109+
# Mock database file doesn't exist
110+
with patch("pathlib.Path.exists", return_value=False):
111+
with patch("pathlib.Path.unlink") as mock_unlink:
112+
with patch("basic_memory.cli.commands.db.asyncio.run") as mock_run:
113+
# Run the reset command
114+
result = runner.invoke(cli_app, ["db", "reset"])
115+
116+
# Should exit successfully
117+
assert result.exit_code == 0
118+
119+
# Database file deletion should not be attempted
120+
mock_unlink.assert_not_called()
121+
122+
# But migrations should still run
123+
mock_run.assert_called_once()
124+
125+
# Configuration should still be reset
126+
expected_projects = {"main": str(Path.home() / "basic-memory")}
127+
assert config_manager.config.projects == expected_projects
128+
assert config_manager.config.default_project == "main"

0 commit comments

Comments
 (0)