diff --git a/KNOWN_ISSUES.md b/KNOWN_ISSUES.md index a513eb4..f4529d7 100644 --- a/KNOWN_ISSUES.md +++ b/KNOWN_ISSUES.md @@ -23,23 +23,26 @@ | 工具 | Tier | 已有覆盖 | |------|------|----------| -| `devkit_index_health` | Beta | 无 | -| `devkit_index_stream` | Beta | 无 | -| `devkit_note` | Beta | 无 | | `devkit_digest` | Experimental | 无 | | `devkit_paper_index` | Experimental | 无 | | `devkit_embedding_store` | Beta | 无 | | `devkit_embedding_search` | Beta | 无 | -| `devkit_related_symbols` | Experimental | 无 | -| `devkit_search_quality` | Beta | 无 | | `devkit_impact_analysis` | Beta | 无 | | `devkit_project_brief` | Beta | 间接(scenario) | -| `devkit_knowledge_report` | Beta | 间接(scenario) | | `devkit_session_*` × 13 | Beta/Exp | 部分 smoke;save/list/resume 已有覆盖 | -| `devkit_evaluate` | Beta | smoke | -| `devkit_ontology_import` | Beta | smoke | -**建议**:按调用频率排序,持续为 IndexHealth、Session 记忆召回、OntologyImport、Embedding 相关工具添加 dedicated 测试。 +**已补充 dedicated invocation 测试**: +- `devkit_index_health` +- `devkit_index_stream` +- `devkit_note` +- `devkit_evaluate` +- `devkit_ontology_import` +- `devkit_search_quality` +- `devkit_related_symbols` +- `devkit_knowledge_report` +- `devkit_experiment_log` + +**建议**:按调用频率排序,持续为 Embedding 相关工具、ImpactAnalysis、ProjectBrief、Session 记忆召回添加 dedicated 测试。 --- diff --git a/src/mcp/tests.rs b/src/mcp/tests.rs index defd275..fa97255 100644 --- a/src/mcp/tests.rs +++ b/src/mcp/tests.rs @@ -980,3 +980,223 @@ async fn test_scenario_two_semantic_exploration() { "vault_search should return auth-design note" ); } + +#[tokio::test] +async fn test_tools_call_devkit_index_health() { + let server = build_server(); + let req = serde_json::json!({ + "jsonrpc": "2.0", + "id": 19, + "method": "tools/call", + "params": { + "name": "devkit_index_health", + "arguments": { "repair": false } + } + }); + let (mut ctx, _tmp) = test_ctx(); + let resp = server.handle_request(req, &mut ctx).await.unwrap(); + let result = resp.get("result").unwrap(); + let content = result.get("content").unwrap().as_array().unwrap(); + let text = content[0].get("text").unwrap().as_str().unwrap(); + let parsed: serde_json::Value = serde_json::from_str(text).unwrap(); + assert!(parsed.get("overall_score").unwrap().as_i64().is_some()); +} + +#[tokio::test] +async fn test_tools_call_devkit_index_stream() { + let server = build_server(); + let req = serde_json::json!({ + "jsonrpc": "2.0", + "id": 20, + "method": "tools/call", + "params": { + "name": "devkit_index_stream", + "arguments": {} + } + }); + let (mut ctx, _tmp) = test_ctx(); + let resp = server.handle_request(req, &mut ctx).await.unwrap(); + let result = resp.get("result").unwrap(); + let content = result.get("content").unwrap().as_array().unwrap(); + let text = content[0].get("text").unwrap().as_str().unwrap(); + let parsed: serde_json::Value = serde_json::from_str(text).unwrap(); + assert_eq!(parsed.get("success").unwrap(), true); + assert!(parsed.get("indexed").unwrap().as_i64().unwrap() >= 0); +} + +#[tokio::test] +async fn test_tools_call_devkit_note() { + let server = build_server(); + let (mut ctx, _tmp) = test_ctx(); + seed_repo(&ctx, "note-repo", "rust"); + + let req = serde_json::json!({ + "jsonrpc": "2.0", + "id": 21, + "method": "tools/call", + "params": { + "name": "devkit_note", + "arguments": { + "repo_id": "note-repo", + "text": "This is a test discovery note.", + "author": "test" + } + } + }); + let resp = server.handle_request(req, &mut ctx).await.unwrap(); + let result = resp.get("result").unwrap(); + let content = result.get("content").unwrap().as_array().unwrap(); + let text = content[0].get("text").unwrap().as_str().unwrap(); + let parsed: serde_json::Value = serde_json::from_str(text).unwrap(); + assert_eq!(parsed.get("success").unwrap(), true); +} + +#[tokio::test] +async fn test_tools_call_devkit_evaluate() { + let server = build_server(); + let req = serde_json::json!({ + "jsonrpc": "2.0", + "id": 22, + "method": "tools/call", + "params": { + "name": "devkit_evaluate", + "arguments": { "scope": "check_only" } + } + }); + let (mut ctx, _tmp) = test_ctx(); + let resp = server.handle_request(req, &mut ctx).await.unwrap(); + let result = resp.get("result").unwrap(); + let content = result.get("content").unwrap().as_array().unwrap(); + let text = content[0].get("text").unwrap().as_str().unwrap(); + let parsed: serde_json::Value = serde_json::from_str(text).unwrap(); + assert_eq!(parsed.get("success").unwrap(), true); + assert!(parsed.get("check").unwrap().is_object()); + assert!(parsed.get("clippy").unwrap().is_object()); + assert!(parsed.get("fmt").unwrap().is_object()); +} + +#[tokio::test] +async fn test_tools_call_devkit_ontology_import_not_found() { + let server = build_server(); + let req = serde_json::json!({ + "jsonrpc": "2.0", + "id": 23, + "method": "tools/call", + "params": { + "name": "devkit_ontology_import", + "arguments": { + "path": "/nonexistent/ontology.json", + "dry_run": true + } + } + }); + let (mut ctx, _tmp) = test_ctx(); + let resp = server.handle_request(req, &mut ctx).await.unwrap(); + let result = resp.get("result").unwrap(); + let content = result.get("content").unwrap().as_array().unwrap(); + let text = content[0].get("text").unwrap().as_str().unwrap(); + let parsed: serde_json::Value = serde_json::from_str(text).unwrap(); + assert_eq!(parsed.get("success").unwrap(), false); +} + +#[tokio::test] +async fn test_tools_call_devkit_search_quality() { + let server = build_server(); + let req = serde_json::json!({ + "jsonrpc": "2.0", + "id": 24, + "method": "tools/call", + "params": { + "name": "devkit_search_quality", + "arguments": { + "repo_id": "scenario-repo", + "query_text": "authentication flow", + "limit": 5 + } + } + }); + let (mut ctx, _tmp) = test_ctx(); + seed_repo(&ctx, "scenario-repo", "rust"); + let resp = server.handle_request(req, &mut ctx).await.unwrap(); + let result = resp.get("result").unwrap(); + let content = result.get("content").unwrap().as_array().unwrap(); + let text = content[0].get("text").unwrap().as_str().unwrap(); + let parsed: serde_json::Value = serde_json::from_str(text).unwrap(); + assert_eq!(parsed.get("success").unwrap(), true); + assert!(parsed.get("keyword_recall").unwrap().is_number()); +} + +#[tokio::test] +async fn test_tools_call_devkit_related_symbols() { + let server = build_server(); + let req = serde_json::json!({ + "jsonrpc": "2.0", + "id": 25, + "method": "tools/call", + "params": { + "name": "devkit_related_symbols", + "arguments": { + "repo_id": "scenario-repo", + "symbol_name": "authenticate_user", + "limit": 5 + } + } + }); + let (mut ctx, _tmp) = test_ctx(); + seed_repo(&ctx, "scenario-repo", "rust"); + let resp = server.handle_request(req, &mut ctx).await.unwrap(); + let result = resp.get("result").unwrap(); + let content = result.get("content").unwrap().as_array().unwrap(); + let text = content[0].get("text").unwrap().as_str().unwrap(); + let parsed: serde_json::Value = serde_json::from_str(text).unwrap(); + assert_eq!(parsed.get("success").unwrap(), true); + assert!(parsed.get("links").unwrap().is_array()); +} + +#[tokio::test] +async fn test_tools_call_devkit_knowledge_report() { + let server = build_server(); + let req = serde_json::json!({ + "jsonrpc": "2.0", + "id": 26, + "method": "tools/call", + "params": { + "name": "devkit_knowledge_report", + "arguments": {} + } + }); + let (mut ctx, _tmp) = test_ctx(); + let resp = server.handle_request(req, &mut ctx).await.unwrap(); + let result = resp.get("result").unwrap(); + let content = result.get("content").unwrap().as_array().unwrap(); + let text = content[0].get("text").unwrap().as_str().unwrap(); + let parsed: serde_json::Value = serde_json::from_str(text).unwrap(); + assert_eq!(parsed.get("success").unwrap(), true); + assert!(parsed.get("report").unwrap().get("repo_count").unwrap().as_i64().is_some()); +} + +#[tokio::test] +async fn test_tools_call_devkit_experiment_log() { + let server = build_server(); + let req = serde_json::json!({ + "jsonrpc": "2.0", + "id": 27, + "method": "tools/call", + "params": { + "name": "devkit_experiment_log", + "arguments": { + "id": "exp-001", + "repo_id": "scenario-repo", + "status": "completed" + } + } + }); + let (mut ctx, _tmp) = test_ctx(); + seed_repo(&ctx, "scenario-repo", "rust"); + let resp = server.handle_request(req, &mut ctx).await.unwrap(); + let result = resp.get("result").unwrap(); + let content = result.get("content").unwrap().as_array().unwrap(); + let text = content[0].get("text").unwrap().as_str().unwrap(); + let parsed: serde_json::Value = serde_json::from_str(text).unwrap(); + assert_eq!(parsed.get("success").unwrap(), true); +}