refactor: 清理未使用代码并添加未来功能标记
Some checks failed
CI / Rust Check (push) Has been cancelled
CI / Lint & TypeCheck (push) Has been cancelled
CI / Unit Tests (push) Has been cancelled
CI / Build Frontend (push) Has been cancelled
CI / Security Scan (push) Has been cancelled
CI / E2E Tests (push) Has been cancelled
Some checks failed
CI / Rust Check (push) Has been cancelled
CI / Lint & TypeCheck (push) Has been cancelled
CI / Unit Tests (push) Has been cancelled
CI / Build Frontend (push) Has been cancelled
CI / Security Scan (push) Has been cancelled
CI / E2E Tests (push) Has been cancelled
style: 统一代码格式和注释风格 docs: 更新多个功能文档的完整度和状态 feat(runtime): 添加路径验证工具支持 fix(pipeline): 改进条件判断和变量解析逻辑 test(types): 为ID类型添加全面测试用例 chore: 更新依赖项和Cargo.lock文件 perf(mcp): 优化MCP协议传输和错误处理
This commit is contained in:
@@ -278,3 +278,334 @@ impl MemoryStore {
|
||||
Ok(rows.into_iter().map(|(key,)| key).collect())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use zclaw_types::{AgentConfig, ModelConfig};
|
||||
|
||||
fn create_test_agent_config(name: &str) -> AgentConfig {
|
||||
AgentConfig {
|
||||
id: AgentId::new(),
|
||||
name: name.to_string(),
|
||||
description: None,
|
||||
model: ModelConfig::default(),
|
||||
system_prompt: None,
|
||||
capabilities: vec![],
|
||||
tools: vec![],
|
||||
max_tokens: None,
|
||||
temperature: None,
|
||||
enabled: true,
|
||||
}
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_in_memory_store_creation() {
|
||||
let store = MemoryStore::in_memory().await;
|
||||
assert!(store.is_ok());
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_save_and_load_agent() {
|
||||
let store = MemoryStore::in_memory().await.unwrap();
|
||||
let config = create_test_agent_config("test-agent");
|
||||
|
||||
store.save_agent(&config).await.unwrap();
|
||||
|
||||
let loaded = store.load_agent(&config.id).await.unwrap();
|
||||
assert!(loaded.is_some());
|
||||
let loaded = loaded.unwrap();
|
||||
assert_eq!(loaded.id, config.id);
|
||||
assert_eq!(loaded.name, config.name);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_load_nonexistent_agent() {
|
||||
let store = MemoryStore::in_memory().await.unwrap();
|
||||
let fake_id = AgentId::new();
|
||||
|
||||
let result = store.load_agent(&fake_id).await.unwrap();
|
||||
assert!(result.is_none());
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_save_agent_updates_existing() {
|
||||
let store = MemoryStore::in_memory().await.unwrap();
|
||||
let mut config = create_test_agent_config("original");
|
||||
|
||||
store.save_agent(&config).await.unwrap();
|
||||
|
||||
config.name = "updated".to_string();
|
||||
store.save_agent(&config).await.unwrap();
|
||||
|
||||
let loaded = store.load_agent(&config.id).await.unwrap().unwrap();
|
||||
assert_eq!(loaded.name, "updated");
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_list_agents() {
|
||||
let store = MemoryStore::in_memory().await.unwrap();
|
||||
|
||||
let config1 = create_test_agent_config("agent1");
|
||||
let config2 = create_test_agent_config("agent2");
|
||||
|
||||
store.save_agent(&config1).await.unwrap();
|
||||
store.save_agent(&config2).await.unwrap();
|
||||
|
||||
let agents = store.list_agents().await.unwrap();
|
||||
assert_eq!(agents.len(), 2);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_delete_agent() {
|
||||
let store = MemoryStore::in_memory().await.unwrap();
|
||||
let config = create_test_agent_config("to-delete");
|
||||
|
||||
store.save_agent(&config).await.unwrap();
|
||||
store.delete_agent(&config.id).await.unwrap();
|
||||
|
||||
let loaded = store.load_agent(&config.id).await.unwrap();
|
||||
assert!(loaded.is_none());
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_delete_nonexistent_agent_succeeds() {
|
||||
let store = MemoryStore::in_memory().await.unwrap();
|
||||
let fake_id = AgentId::new();
|
||||
|
||||
// Deleting nonexistent agent should succeed (idempotent)
|
||||
let result = store.delete_agent(&fake_id).await;
|
||||
assert!(result.is_ok());
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_create_session() {
|
||||
let store = MemoryStore::in_memory().await.unwrap();
|
||||
let config = create_test_agent_config("session-test");
|
||||
|
||||
store.save_agent(&config).await.unwrap();
|
||||
|
||||
let session_id = store.create_session(&config.id).await.unwrap();
|
||||
assert!(!session_id.as_uuid().is_nil());
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_append_and_get_messages() {
|
||||
let store = MemoryStore::in_memory().await.unwrap();
|
||||
let config = create_test_agent_config("msg-test");
|
||||
|
||||
store.save_agent(&config).await.unwrap();
|
||||
let session_id = store.create_session(&config.id).await.unwrap();
|
||||
|
||||
let msg1 = Message::user("Hello");
|
||||
let msg2 = Message::assistant("Hi there!");
|
||||
|
||||
store.append_message(&session_id, &msg1).await.unwrap();
|
||||
store.append_message(&session_id, &msg2).await.unwrap();
|
||||
|
||||
let messages = store.get_messages(&session_id).await.unwrap();
|
||||
assert_eq!(messages.len(), 2);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_message_ordering() {
|
||||
let store = MemoryStore::in_memory().await.unwrap();
|
||||
let config = create_test_agent_config("order-test");
|
||||
|
||||
store.save_agent(&config).await.unwrap();
|
||||
let session_id = store.create_session(&config.id).await.unwrap();
|
||||
|
||||
for i in 0..10 {
|
||||
let msg = Message::user(format!("Message {}", i));
|
||||
store.append_message(&session_id, &msg).await.unwrap();
|
||||
}
|
||||
|
||||
let messages = store.get_messages(&session_id).await.unwrap();
|
||||
assert_eq!(messages.len(), 10);
|
||||
|
||||
// Verify ordering
|
||||
for (i, msg) in messages.iter().enumerate() {
|
||||
if let Message::User { content } = msg {
|
||||
assert_eq!(content, &format!("Message {}", i));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_kv_store_and_recall() {
|
||||
let store = MemoryStore::in_memory().await.unwrap();
|
||||
let config = create_test_agent_config("kv-test");
|
||||
|
||||
store.save_agent(&config).await.unwrap();
|
||||
|
||||
let value = serde_json::json!({"key": "value", "number": 42});
|
||||
store.kv_store(&config.id, "test-key", &value).await.unwrap();
|
||||
|
||||
let recalled = store.kv_recall(&config.id, "test-key").await.unwrap();
|
||||
assert!(recalled.is_some());
|
||||
assert_eq!(recalled.unwrap(), value);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_kv_recall_nonexistent() {
|
||||
let store = MemoryStore::in_memory().await.unwrap();
|
||||
let config = create_test_agent_config("kv-missing");
|
||||
|
||||
store.save_agent(&config).await.unwrap();
|
||||
|
||||
let result = store.kv_recall(&config.id, "nonexistent").await.unwrap();
|
||||
assert!(result.is_none());
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_kv_update_existing() {
|
||||
let store = MemoryStore::in_memory().await.unwrap();
|
||||
let config = create_test_agent_config("kv-update");
|
||||
|
||||
store.save_agent(&config).await.unwrap();
|
||||
|
||||
let value1 = serde_json::json!({"version": 1});
|
||||
let value2 = serde_json::json!({"version": 2});
|
||||
|
||||
store.kv_store(&config.id, "key", &value1).await.unwrap();
|
||||
store.kv_store(&config.id, "key", &value2).await.unwrap();
|
||||
|
||||
let recalled = store.kv_recall(&config.id, "key").await.unwrap().unwrap();
|
||||
assert_eq!(recalled["version"], 2);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_kv_list() {
|
||||
let store = MemoryStore::in_memory().await.unwrap();
|
||||
let config = create_test_agent_config("kv-list");
|
||||
|
||||
store.save_agent(&config).await.unwrap();
|
||||
|
||||
store.kv_store(&config.id, "key1", &serde_json::json!(1)).await.unwrap();
|
||||
store.kv_store(&config.id, "key2", &serde_json::json!(2)).await.unwrap();
|
||||
store.kv_store(&config.id, "key3", &serde_json::json!(3)).await.unwrap();
|
||||
|
||||
let keys = store.kv_list(&config.id).await.unwrap();
|
||||
assert_eq!(keys.len(), 3);
|
||||
assert!(keys.contains(&"key1".to_string()));
|
||||
assert!(keys.contains(&"key2".to_string()));
|
||||
assert!(keys.contains(&"key3".to_string()));
|
||||
}
|
||||
|
||||
// === Edge Case Tests ===
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_agent_with_empty_name() {
|
||||
let store = MemoryStore::in_memory().await.unwrap();
|
||||
let config = create_test_agent_config("");
|
||||
|
||||
// Empty name should still work (validation is elsewhere)
|
||||
let result = store.save_agent(&config).await;
|
||||
assert!(result.is_ok());
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_agent_with_special_characters_in_name() {
|
||||
let store = MemoryStore::in_memory().await.unwrap();
|
||||
let config = create_test_agent_config("agent-with-特殊字符-🎉");
|
||||
|
||||
let result = store.save_agent(&config).await;
|
||||
assert!(result.is_ok());
|
||||
|
||||
let loaded = store.load_agent(&config.id).await.unwrap().unwrap();
|
||||
assert_eq!(loaded.name, "agent-with-特殊字符-🎉");
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_large_message_content() {
|
||||
let store = MemoryStore::in_memory().await.unwrap();
|
||||
let config = create_test_agent_config("large-msg");
|
||||
|
||||
store.save_agent(&config).await.unwrap();
|
||||
let session_id = store.create_session(&config.id).await.unwrap();
|
||||
|
||||
// Create a large message (100KB)
|
||||
let large_content = "x".repeat(100_000);
|
||||
let msg = Message::user(&large_content);
|
||||
|
||||
let result = store.append_message(&session_id, &msg).await;
|
||||
assert!(result.is_ok());
|
||||
|
||||
let messages = store.get_messages(&session_id).await.unwrap();
|
||||
assert_eq!(messages.len(), 1);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_message_with_tool_use() {
|
||||
let store = MemoryStore::in_memory().await.unwrap();
|
||||
let config = create_test_agent_config("tool-msg");
|
||||
|
||||
store.save_agent(&config).await.unwrap();
|
||||
let session_id = store.create_session(&config.id).await.unwrap();
|
||||
|
||||
let tool_input = serde_json::json!({"query": "test", "options": {"limit": 10}});
|
||||
let msg = Message::tool_use("call-123", zclaw_types::ToolId::new("search"), tool_input.clone());
|
||||
|
||||
store.append_message(&session_id, &msg).await.unwrap();
|
||||
|
||||
let messages = store.get_messages(&session_id).await.unwrap();
|
||||
assert_eq!(messages.len(), 1);
|
||||
|
||||
if let Message::ToolUse { id, tool, input } = &messages[0] {
|
||||
assert_eq!(id, "call-123");
|
||||
assert_eq!(tool.as_str(), "search");
|
||||
assert_eq!(*input, tool_input);
|
||||
} else {
|
||||
panic!("Expected ToolUse message");
|
||||
}
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_message_with_tool_result() {
|
||||
let store = MemoryStore::in_memory().await.unwrap();
|
||||
let config = create_test_agent_config("tool-result");
|
||||
|
||||
store.save_agent(&config).await.unwrap();
|
||||
let session_id = store.create_session(&config.id).await.unwrap();
|
||||
|
||||
let output = serde_json::json!({"results": ["a", "b", "c"]});
|
||||
let msg = Message::tool_result("call-123", zclaw_types::ToolId::new("search"), output.clone(), false);
|
||||
|
||||
store.append_message(&session_id, &msg).await.unwrap();
|
||||
|
||||
let messages = store.get_messages(&session_id).await.unwrap();
|
||||
assert_eq!(messages.len(), 1);
|
||||
|
||||
if let Message::ToolResult { tool_call_id, tool, output: o, is_error } = &messages[0] {
|
||||
assert_eq!(tool_call_id, "call-123");
|
||||
assert_eq!(tool.as_str(), "search");
|
||||
assert_eq!(*o, output);
|
||||
assert!(!is_error);
|
||||
} else {
|
||||
panic!("Expected ToolResult message");
|
||||
}
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_message_with_thinking() {
|
||||
let store = MemoryStore::in_memory().await.unwrap();
|
||||
let config = create_test_agent_config("thinking");
|
||||
|
||||
store.save_agent(&config).await.unwrap();
|
||||
let session_id = store.create_session(&config.id).await.unwrap();
|
||||
|
||||
let msg = Message::assistant_with_thinking("Final answer", "My reasoning...");
|
||||
|
||||
store.append_message(&session_id, &msg).await.unwrap();
|
||||
|
||||
let messages = store.get_messages(&session_id).await.unwrap();
|
||||
assert_eq!(messages.len(), 1);
|
||||
|
||||
if let Message::Assistant { content, thinking } = &messages[0] {
|
||||
assert_eq!(content, "Final answer");
|
||||
assert_eq!(thinking.as_ref().unwrap(), "My reasoning...");
|
||||
} else {
|
||||
panic!("Expected Assistant message");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user