"""剩余覆盖率测试 - 覆盖最后的边缘情况."""
import pytest
import os
import asyncio
from unittest.mock import Mock, MagicMock, patch, AsyncMock
from pathlib import Path
from src.config_manager import ConfigManager
from src.graphiti_client import GraphitiClient
class TestGraphitiClientCheckReconnect:
"""测试 GraphitiClient check_reconnect 方法."""
@pytest.fixture
def config_manager(self, temp_config_dir):
"""创建配置管理器."""
return ConfigManager(config_path=temp_config_dir / ".graphitiace" / "config.json")
def test_check_reconnect_config_changed(self, config_manager):
"""测试配置变更时重连."""
client = GraphitiClient(config_manager)
# 配置 Neo4j
config_manager.configure_neo4j(
uri="bolt://localhost:7687",
username="neo4j",
password="test"
)
# Mock driver 和连接状态
mock_driver = MagicMock()
mock_session = MagicMock()
mock_driver.session.return_value.__enter__ = MagicMock(return_value=mock_session)
mock_driver.session.return_value.__exit__ = MagicMock(return_value=None)
client.driver = mock_driver
client._connected = True
client._last_neo4j_config = {"uri": "bolt://old:7687"} # 旧配置
# Mock connect 方法
with patch.object(client, 'connect', return_value=True) as mock_connect:
with patch.object(client, 'disconnect') as mock_disconnect:
result = client.check_reconnect()
# 应该检测到配置变更
mock_disconnect.assert_called_once()
mock_connect.assert_called_once()
def test_check_reconnect_api_config_changed(self, config_manager):
"""测试 API 配置变更时重新初始化 Graphiti."""
client = GraphitiClient(config_manager)
# 配置 Neo4j
config_manager.configure_neo4j(
uri="bolt://localhost:7687",
username="neo4j",
password="test"
)
# 设置连接状态
mock_driver = MagicMock()
client.driver = mock_driver
client._connected = True
# 设置旧配置
client._last_neo4j_config = config_manager.get_neo4j_config().model_dump()
client._last_api_config = None # 旧 API 配置为空
# 配置新的 API
config_manager.configure_api(
provider="openai",
api_key="new_key",
model="gpt-4"
)
# Mock _initialize_graphiti
with patch.object(client, '_initialize_graphiti', return_value=True) as mock_init:
result = client.check_reconnect()
# 应该重新初始化 Graphiti
mock_init.assert_called_once()
assert result is True
class TestGraphitiClientDisconnect:
"""测试 GraphitiClient disconnect 方法."""
@pytest.fixture
def config_manager(self, temp_config_dir):
"""创建配置管理器."""
return ConfigManager(config_path=temp_config_dir / ".graphitiace" / "config.json")
def test_disconnect_with_graphiti_close_in_event_loop(self, config_manager):
"""测试在事件循环中断开连接时关闭 Graphiti."""
client = GraphitiClient(config_manager)
# 创建 mock graphiti 对象
mock_graphiti = MagicMock()
mock_close_coro = AsyncMock()
mock_graphiti.close = MagicMock(return_value=mock_close_coro())
client.graphiti = mock_graphiti
# 创建 mock driver
mock_driver = MagicMock()
client.driver = mock_driver
client._connected = True
# 调用 disconnect
client.disconnect()
# 验证状态已清理
assert client.driver is None
assert client.graphiti is None
assert client._connected is False
def test_disconnect_without_graphiti(self, config_manager):
"""测试断开连接时没有 Graphiti 实例."""
client = GraphitiClient(config_manager)
# 只有 driver,没有 graphiti
mock_driver = MagicMock()
client.driver = mock_driver
client._connected = True
client.graphiti = None
# 调用 disconnect
client.disconnect()
# 验证状态已清理
assert client.driver is None
assert client._connected is False
class TestServerCallToolArgumentsNone:
"""测试 server.py 中 arguments 为 None 的情况."""
def test_server_call_tool_logic_none_args(self):
"""测试 call_tool 逻辑处理 None 参数."""
# 模拟 server.py 中的逻辑
arguments = None
if arguments is None:
arguments = {}
assert arguments == {}
def test_server_call_tool_logic_empty_args(self):
"""测试 call_tool 逻辑处理空字典参数."""
arguments = {}
if arguments is None:
arguments = {}
assert arguments == {}
class TestServerReconnectFailure:
"""测试 server.py 中重连失败的情况."""
@pytest.fixture
def config_manager(self, temp_config_dir):
"""创建配置管理器."""
return ConfigManager(config_path=temp_config_dir / ".graphitiace" / "config.json")
def test_graphiti_client_check_reconnect_exception(self, config_manager):
"""测试 check_reconnect 抛出异常."""
client = GraphitiClient(config_manager)
# Mock check_reconnect 抛出异常
with patch.object(client, 'check_reconnect', side_effect=Exception("reconnect failed")):
try:
client.check_reconnect()
except Exception as e:
# 异常应该被捕获
assert "reconnect failed" in str(e)
class TestACEManagerDefaultModel:
"""测试 ACE Manager 使用默认模型."""
@pytest.fixture
def fresh_config_manager(self, temp_config_dir):
"""创建全新的配置管理器."""
fresh_path = temp_config_dir / ".graphitiace_ace" / "config.json"
fresh_path.parent.mkdir(parents=True, exist_ok=True)
return ConfigManager(config_path=fresh_path)
def test_ace_manager_no_api_config(self, fresh_config_manager):
"""测试 ACE Manager 没有 API 配置时使用默认模型."""
try:
from src.ace_manager import ACEManager
from src.graphiti_client import GraphitiClient
graphiti_client = GraphitiClient(fresh_config_manager)
# 不配置 API
ace_manager = ACEManager(fresh_config_manager, graphiti_client)
# ACE Manager 应该使用默认模型
assert ace_manager is not None
except ImportError:
pytest.skip("ace-framework not installed")
class TestHealthCheckDegradedStatusDirect:
"""直接测试健康检查 degraded 状态逻辑."""
def test_health_check_degraded_logic(self):
"""测试 degraded 状态判断逻辑."""
# 模拟健康检查结果
result = {
"status": "healthy",
"checks": {
"neo4j": {"status": "healthy"},
"config": {"status": "warning"}
}
}
check_statuses = [check.get("status") for check in result["checks"].values()]
if "error" in check_statuses:
result["status"] = "unhealthy"
elif "warning" in check_statuses:
result["status"] = "degraded"
assert result["status"] == "degraded"
def test_health_check_unhealthy_logic(self):
"""测试 unhealthy 状态判断逻辑."""
result = {
"status": "healthy",
"checks": {
"neo4j": {"status": "error"},
"config": {"status": "warning"}
}
}
check_statuses = [check.get("status") for check in result["checks"].values()]
if "error" in check_statuses:
result["status"] = "unhealthy"
elif "warning" in check_statuses:
result["status"] = "degraded"
assert result["status"] == "unhealthy"
class TestNeo4jDateTimeEdgeCases:
"""测试 Neo4j DateTime 边缘情况."""
def test_neo4j_datetime_none(self):
"""测试 Neo4jDateTime 为 None 的情况."""
from src.graphiti_client import _neo4j_to_dict, Neo4jDateTime
# 如果 Neo4jDateTime 为 None(导入失败)
if Neo4jDateTime is None:
# 应该正常处理
result = _neo4j_to_dict("test")
assert result == "test"