refactor(backend): phase 4 - add test hooks and extend service layer

- Extract internal functions in commands/mcp.rs and commands/provider.rs
  to enable unit testing without Tauri context
- Add test hooks: set_mcp_enabled_test_hook, import_mcp_from_claude_test_hook,
  import_mcp_from_codex_test_hook, import_default_config_test_hook
- Migrate error types from String to AppError for precise error matching in tests
- Extend ProviderService with delete() method to unify Codex/Claude cleanup logic
- Add comprehensive test coverage:
  - tests/mcp_commands.rs: command-level tests for MCP operations
  - tests/provider_service.rs: service-level tests for switch/delete operations
- Run cargo fmt to fix formatting issues (EOF newlines)
- Update BACKEND_REFACTOR_PLAN.md to mark phase 3 complete
This commit is contained in:
Jason
2025-10-28 11:58:57 +08:00
parent c2e8855a0f
commit 7e27f88154
20 changed files with 1005 additions and 415 deletions

View File

@@ -66,8 +66,7 @@ fn read_json_value(path: &Path) -> Result<Value, AppError> {
return Ok(serde_json::json!({}));
}
let content = fs::read_to_string(path).map_err(|e| AppError::io(path, e))?;
let value: Value =
serde_json::from_str(&content).map_err(|e| AppError::json(path, e))?;
let value: Value = serde_json::from_str(&content).map_err(|e| AppError::json(path, e))?;
Ok(value)
}
@@ -108,9 +107,7 @@ pub fn read_mcp_json() -> Result<Option<String>, AppError> {
pub fn upsert_mcp_server(id: &str, spec: Value) -> Result<bool, AppError> {
if id.trim().is_empty() {
return Err(AppError::InvalidInput(
"MCP 服务器 ID 不能为空".into(),
));
return Err(AppError::InvalidInput("MCP 服务器 ID 不能为空".into()));
}
// 基础字段校验(尽量宽松)
if !spec.is_object() {
@@ -179,9 +176,7 @@ pub fn upsert_mcp_server(id: &str, spec: Value) -> Result<bool, AppError> {
pub fn delete_mcp_server(id: &str) -> Result<bool, AppError> {
if id.trim().is_empty() {
return Err(AppError::InvalidInput(
"MCP 服务器 ID 不能为空".into(),
));
return Err(AppError::InvalidInput("MCP 服务器 ID 不能为空".into()));
}
let path = user_config_path();
if !path.exists() {
@@ -261,15 +256,9 @@ pub fn set_mcp_servers_map(
};
if let Some(server_val) = obj.remove("server") {
let server_obj = server_val
.as_object()
.cloned()
.ok_or_else(|| {
AppError::McpValidation(format!(
"MCP 服务器 '{}' server 字段不是对象",
id
))
})?;
let server_obj = server_val.as_object().cloned().ok_or_else(|| {
AppError::McpValidation(format!("MCP 服务器 '{}' server 字段不是对象", id))
})?;
obj = server_obj;
}