- 合并 server.py 到 core/__init__.py,使用统一 Packet 协议 - 后端管理配置持久化 (~/.trulymem/config.json) - 前端移除 ConfigService,通过 BackendClient 与后端通信 - 删除 UI 中冗余的 AI 推理逻辑 (chat_service, tool_service, message_handler) - 删除 core/tools 重复文件 (tool_executor, tool_limiter) - 提示词管理器支持用户自定义 (~/.trulyemem/system_prompt.md) - 启动入口优化配置路径逻辑 - 更新测试覆盖 (42 tests) - 更新文档
179 lines
6.5 KiB
Python
179 lines
6.5 KiB
Python
import pytest
|
||
import os
|
||
import tempfile
|
||
|
||
os.environ["DEEPSEEK_API_KEY"] = "fake-test-key"
|
||
|
||
|
||
class TestIntegrationPacketFlow:
|
||
"""测试 Packet 通信流程"""
|
||
|
||
def test_packet_round_trip_process_message(self):
|
||
from core import BackendServer, BackendClient
|
||
with tempfile.NamedTemporaryFile(suffix=".db", delete=False) as f:
|
||
db_path = f.name
|
||
try:
|
||
server = BackendServer(db_path=db_path, use_embedded_db=True)
|
||
server.start(api_key="")
|
||
client = BackendClient(server)
|
||
|
||
# 无 API key 时应该返回错误而非抛异常
|
||
result = client.process_message("test message")
|
||
assert result.get("success") is False
|
||
assert "error" in result
|
||
|
||
server.shutdown()
|
||
finally:
|
||
if os.path.exists(db_path):
|
||
os.unlink(db_path)
|
||
|
||
def test_packet_round_trip_config(self):
|
||
from core import BackendServer, BackendClient
|
||
with tempfile.NamedTemporaryFile(suffix=".db", delete=False) as f:
|
||
db_path = f.name
|
||
try:
|
||
server = BackendServer(db_path=db_path, use_embedded_db=True)
|
||
server.start(api_key="")
|
||
client = BackendClient(server)
|
||
|
||
result = client.update_config(api_key="test-api", base_url="https://test.com")
|
||
assert result.get("success") is True
|
||
|
||
status = client.get_status()
|
||
data = status.get("data", {})
|
||
assert data.get("config", {}).get("api_key") == "test-api"
|
||
assert data.get("config", {}).get("base_url") == "https://test.com"
|
||
|
||
server.shutdown()
|
||
finally:
|
||
if os.path.exists(db_path):
|
||
os.unlink(db_path)
|
||
|
||
def test_packet_round_trip_status(self):
|
||
from core import BackendServer, BackendClient
|
||
with tempfile.NamedTemporaryFile(suffix=".db", delete=False) as f:
|
||
db_path = f.name
|
||
try:
|
||
server = BackendServer(db_path=db_path, use_embedded_db=True)
|
||
server.start(api_key="")
|
||
client = BackendClient(server)
|
||
|
||
result = client.get_status()
|
||
assert result.get("success") is True
|
||
data = result.get("data", {})
|
||
assert data.get("running") is True
|
||
assert data.get("graph_initialized") is True
|
||
|
||
server.shutdown()
|
||
finally:
|
||
if os.path.exists(db_path):
|
||
os.unlink(db_path)
|
||
|
||
def test_packet_round_trip_execute_tool(self):
|
||
from core import BackendServer, BackendClient
|
||
with tempfile.NamedTemporaryFile(suffix=".db", delete=False) as f:
|
||
db_path = f.name
|
||
try:
|
||
server = BackendServer(db_path=db_path, use_embedded_db=True)
|
||
server.start(api_key="")
|
||
client = BackendClient(server)
|
||
|
||
result = client.execute_tool("memory_introspect", {})
|
||
assert result.get("success") is True
|
||
|
||
server.shutdown()
|
||
finally:
|
||
if os.path.exists(db_path):
|
||
os.unlink(db_path)
|
||
|
||
|
||
class TestIntegrationToolLimiter:
|
||
"""测试工具限制器集成"""
|
||
|
||
def test_external_tool_call_not_limited(self):
|
||
from core import BackendServer, BackendClient
|
||
with tempfile.NamedTemporaryFile(suffix=".db", delete=False) as f:
|
||
db_path = f.name
|
||
try:
|
||
server = BackendServer(db_path=db_path, use_embedded_db=True)
|
||
server.start(api_key="")
|
||
client = BackendClient(server)
|
||
|
||
# 外部调用多次应该成功
|
||
for i in range(5):
|
||
result = client.execute_tool("memory_introspect", {})
|
||
assert result.get("success") is True
|
||
|
||
server.shutdown()
|
||
finally:
|
||
if os.path.exists(db_path):
|
||
os.unlink(db_path)
|
||
|
||
def test_internal_tool_call_limited(self):
|
||
from core import BackendServer, BackendClient
|
||
with tempfile.NamedTemporaryFile(suffix=".db", delete=False) as f:
|
||
db_path = f.name
|
||
try:
|
||
server = BackendServer(db_path=db_path, use_embedded_db=True)
|
||
server.start(api_key="fake-key") # 假 key 会失败但不影响测试
|
||
client = BackendClient(server)
|
||
|
||
# 内部调用受限,tool_limiter 存在
|
||
assert server._tool_limiter is not None
|
||
|
||
# 初始状态
|
||
assert server._tool_limiter.counts.persona_update == 0
|
||
|
||
# 记录一次调用
|
||
server._tool_limiter.record_call("persona_update", {})
|
||
assert server._tool_limiter.counts.persona_update == 1
|
||
|
||
# 再次调用应该被拒绝
|
||
allowed, reason = server._tool_limiter.can_call("persona_update", {})
|
||
assert allowed is False
|
||
|
||
server.shutdown()
|
||
finally:
|
||
if os.path.exists(db_path):
|
||
os.unlink(db_path)
|
||
|
||
|
||
class TestIntegrationErrorHandling:
|
||
"""测试错误处理"""
|
||
|
||
def test_process_message_returns_error_not_raise(self):
|
||
from core import BackendServer, BackendClient
|
||
with tempfile.NamedTemporaryFile(suffix=".db", delete=False) as f:
|
||
db_path = f.name
|
||
try:
|
||
server = BackendServer(db_path=db_path, use_embedded_db=True)
|
||
server.start(api_key="")
|
||
client = BackendClient(server)
|
||
|
||
# 应该返回错误,而不是抛出异常
|
||
result = client.process_message("hello")
|
||
assert result.get("success") is False
|
||
assert "error" in result
|
||
|
||
server.shutdown()
|
||
finally:
|
||
if os.path.exists(db_path):
|
||
os.unlink(db_path)
|
||
|
||
def test_execute_tool_error_handling(self):
|
||
from core import BackendServer, BackendClient
|
||
with tempfile.NamedTemporaryFile(suffix=".db", delete=False) as f:
|
||
db_path = f.name
|
||
try:
|
||
server = BackendServer(db_path=db_path, use_embedded_db=True)
|
||
server.start(api_key="")
|
||
client = BackendClient(server)
|
||
|
||
# 不存在的工具应该返回错误
|
||
result = client.execute_tool("nonexistent_tool", {})
|
||
assert result.get("success") is False
|
||
|
||
server.shutdown()
|
||
finally:
|
||
if os.path.exists(db_path):
|
||
os.unlink(db_path) |