-
Notifications
You must be signed in to change notification settings - Fork 216
Expand file tree
/
Copy pathtest_tool_basic_memory_diagnostics.py
More file actions
247 lines (178 loc) · 8.12 KB
/
Copy pathtest_tool_basic_memory_diagnostics.py
File metadata and controls
247 lines (178 loc) · 8.12 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
"""Tests for the basic_memory_diagnostics MCP tool."""
import json
import platform
import sys
from unittest.mock import MagicMock, patch
import basic_memory
from basic_memory.mcp.tools.basic_memory_diagnostics import (
_redact_config,
_redact_url,
basic_memory_diagnostics,
)
# ---------------------------------------------------------------------------
# Unit tests for _redact_config helper
# ---------------------------------------------------------------------------
def test_redact_config_removes_cloud_api_key():
raw = {"cloud_api_key": "bmc_secret", "default_project": "main", "projects": {}}
result = _redact_config(raw)
assert "cloud_api_key" not in result
assert result["default_project"] == "main"
assert "projects" in result
def test_redact_config_passes_through_safe_fields():
raw = {"default_project": "main", "log_level": "INFO", "env": "dev"}
result = _redact_config(raw)
assert result == raw
def test_redact_config_empty_dict():
assert _redact_config({}) == {}
# ---------------------------------------------------------------------------
# Tests for the basic_memory_diagnostics tool
# ---------------------------------------------------------------------------
def test_diagnostics_returns_string():
result = basic_memory_diagnostics()
assert isinstance(result, str)
def test_diagnostics_includes_version():
result = basic_memory_diagnostics()
assert basic_memory.__version__ in result
def test_diagnostics_includes_python_version():
result = basic_memory_diagnostics()
# sys.version can be multi-line; just check the version tuple prefix
major_minor = f"{sys.version_info.major}.{sys.version_info.minor}"
assert major_minor in result
def test_diagnostics_includes_platform():
result = basic_memory_diagnostics()
assert platform.machine() in result
def test_diagnostics_includes_config_path(tmp_path):
"""Config path section should appear in output."""
with patch("basic_memory.mcp.tools.basic_memory_diagnostics.ConfigManager") as MockMgr:
mock_mgr = MagicMock()
mock_mgr.config_dir = tmp_path
MockMgr.return_value = mock_mgr
config_file = tmp_path / "config.json"
config_file.write_text(json.dumps({"default_project": "main", "projects": {}}))
result = basic_memory_diagnostics()
assert str(tmp_path) in result
assert "Config path:" in result
def test_diagnostics_config_exists_with_valid_json(tmp_path):
"""When config file exists, its safe contents should appear as JSON."""
config_data = {
"default_project": "research",
"projects": {"research": {"path": str(tmp_path / "research")}},
}
with patch("basic_memory.mcp.tools.basic_memory_diagnostics.ConfigManager") as MockMgr:
mock_mgr = MagicMock()
mock_mgr.config_dir = tmp_path
MockMgr.return_value = mock_mgr
config_file = tmp_path / "config.json"
config_file.write_text(json.dumps(config_data))
result = basic_memory_diagnostics()
assert "research" in result
assert "```json" in result
def test_diagnostics_redacts_cloud_api_key(tmp_path):
"""cloud_api_key must never appear in diagnostic output."""
config_data = {
"default_project": "main",
"cloud_api_key": "bmc_super_secret_token",
"projects": {},
}
with patch("basic_memory.mcp.tools.basic_memory_diagnostics.ConfigManager") as MockMgr:
mock_mgr = MagicMock()
mock_mgr.config_dir = tmp_path
MockMgr.return_value = mock_mgr
config_file = tmp_path / "config.json"
config_file.write_text(json.dumps(config_data))
result = basic_memory_diagnostics()
assert "bmc_super_secret_token" not in result
assert "cloud_api_key" not in result
def test_diagnostics_config_missing(tmp_path):
"""When config file does not exist, output should say so."""
with patch("basic_memory.mcp.tools.basic_memory_diagnostics.ConfigManager") as MockMgr:
mock_mgr = MagicMock()
mock_mgr.config_dir = tmp_path
MockMgr.return_value = mock_mgr
# Ensure no config.json is present
config_file = tmp_path / "config.json"
assert not config_file.exists()
result = basic_memory_diagnostics()
assert "Config exists: False" in result
assert "<config file not found>" in result
def test_diagnostics_output_sections():
"""All expected section headers should be present."""
result = basic_memory_diagnostics()
assert "# Basic Memory Diagnostics" in result
assert "## Version" in result
assert "## System" in result
assert "## Configuration" in result
# ---------------------------------------------------------------------------
# Unit tests for _redact_url helper
# ---------------------------------------------------------------------------
def test_redact_url_strips_password():
url = "postgresql://user:secret@localhost/mydb"
result = _redact_url(url)
assert "secret" not in result
assert "user" not in result
assert "localhost" in result
assert "mydb" in result
assert "***" in result
def test_redact_url_strips_only_password_when_no_username():
# password-only userinfo (unusual but valid per RFC)
url = "postgresql://:secret@db.example.com/app"
assert _redact_url(url) == "postgresql://***@db.example.com/app"
def test_redact_url_preserves_port():
url = "postgresql://admin:pw@db.internal:5432/prod"
assert _redact_url(url) == "postgresql://***@db.internal:5432/prod"
def test_redact_url_no_credentials_unchanged():
url = "postgresql://db.internal:5432/prod"
assert _redact_url(url) == url
def test_redact_url_non_url_string_unchanged():
# Bare file paths / non-URL values must not be mangled.
path = "/home/user/.local/share/basic-memory/main.db"
assert _redact_url(path) == path
# ---------------------------------------------------------------------------
# _redact_config tests for database_url
# ---------------------------------------------------------------------------
def test_redact_config_scrubs_database_url_credentials():
raw = {
"default_project": "main",
"database_url": "postgresql://dbuser:dbpass@host.example.com:5432/bm",
"projects": {},
}
result = _redact_config(raw)
# Exact match: credentials replaced, host/port/db preserved for diagnostics.
assert result["database_url"] == "postgresql://***@host.example.com:5432/bm"
def test_redact_config_leaves_database_url_without_credentials():
raw = {"database_url": "sqlite:////tmp/basic-memory/main.db"}
result = _redact_config(raw)
assert result["database_url"] == "sqlite:////tmp/basic-memory/main.db"
def test_redact_config_drops_secret_fields_independently():
raw = {
"cloud_api_key": "bmc_top_secret",
"database_url": "postgresql://dbuser:dbpassword@host/db",
"default_project": "main",
}
result = _redact_config(raw)
assert "cloud_api_key" not in result
assert "dbpassword" not in result["database_url"]
assert "dbuser" not in result["database_url"]
assert "main" == result["default_project"]
# ---------------------------------------------------------------------------
# Integration: database_url redaction surfaces in diagnostic output
# ---------------------------------------------------------------------------
def test_diagnostics_redacts_database_url_password(tmp_path):
"""Postgres password in database_url must not appear in diagnostic output."""
config_data = {
"default_project": "main",
"database_url": "postgresql://pguser:supersecret@db.internal:5432/basicmemory",
"projects": {},
}
with patch("basic_memory.mcp.tools.basic_memory_diagnostics.ConfigManager") as MockMgr:
mock_mgr = MagicMock()
mock_mgr.config_dir = tmp_path
MockMgr.return_value = mock_mgr
config_file = tmp_path / "config.json"
config_file.write_text(json.dumps(config_data))
result = basic_memory_diagnostics()
assert "supersecret" not in result
assert "pguser" not in result
# Host and port remain visible for diagnostics.
assert "db.internal" in result
assert "5432" in result