Newer
Older
TelosDB / src / backend / tests / search_api.rs
// MCP search_text API のテスト(MCP が 127.0.0.1:3001 で起動している前提。通常の cargo test ではスキップ)
use reqwest::Client;
use serde_json::json;

#[tokio::test]
#[ignore = "requires MCP server on 127.0.0.1:3001; run with: cargo test --test search_api -- --ignored"]
async fn test_search_text_returns_results() {
    let client = Client::new();
    let req = json!({
        "jsonrpc": "2.0",
        "method": "search_text",
        "params": { "content": "テスト", "limit": 5 },
        "id": 1
    });
    let resp = client
        .post("http://127.0.0.1:3001/messages")
        .json(&req)
        .send()
        .await
        .expect("API呼び出し失敗");
    assert!(resp.status().is_success());
    let body: serde_json::Value = resp.json().await.expect("JSONデコード失敗");
    assert_eq!(body["jsonrpc"], "2.0");
    assert!(body["result"].get("content").is_some());
    assert!(body["result"]["content"].is_array());

    let text = body["result"]["content"][0]["text"].as_str().unwrap_or("");
    let parsed: serde_json::Value = serde_json::from_str(text).unwrap_or(json!(null));
    // 新形式: { items, vector_search_used } であること
    if let Some(obj) = parsed.as_object() {
        assert!(obj.contains_key("items"), "search レスポンスに items があること");
        assert!(
            obj.contains_key("vector_search_used"),
            "search レスポンスに vector_search_used があること(ベクトル検索の有無を判定するため)"
        );
        let items = &obj["items"];
        assert!(items.is_array(), "items は配列");
        if let Some(arr) = items.as_array() {
            for item in arr.iter().take(3) {
                if let Some(sim) = item.get("similarity").and_then(|v| v.as_f64()) {
                    assert!((0.0..=1.0).contains(&sim), "similarity は 0〜1: {}", sim);
                }
            }
        }
    }
}

/// Issue #11: 空クエリでもエラーにせず、統一形式 { items: [], vector_search_used: false } で返ることの検証。
#[tokio::test]
#[ignore = "requires MCP server on 127.0.0.1:3001; run with: cargo test --test search_api -- --ignored"]
async fn test_search_text_empty_query_returns_unified_shape() {
    let client = Client::new();
    let req = json!({
        "jsonrpc": "2.0",
        "method": "search_text",
        "params": { "content": "", "limit": 5 },
        "id": 2
    });
    let resp = client
        .post("http://127.0.0.1:3001/messages")
        .json(&req)
        .send()
        .await
        .expect("API呼び出し失敗");
    assert!(resp.status().is_success(), "空クエリでも 200 であること");
    let body: serde_json::Value = resp.json().await.expect("JSONデコード失敗");
    assert!(body.get("error").is_none(), "JSON-RPC error が無いこと");
    let text = body["result"]["content"][0]["text"].as_str().expect("content[0].text が存在すること");
    let parsed: serde_json::Value = serde_json::from_str(text).expect("content[0].text は JSON であること");
    let obj = parsed.as_object().expect("トップレベルはオブジェクト");
    assert!(obj.contains_key("items"), "items キーがあること");
    assert!(obj.contains_key("vector_search_used"), "vector_search_used キーがあること");
    let items = &obj["items"];
    assert!(items.is_array(), "items は配列");
    assert_eq!(items.as_array().unwrap().len(), 0, "空クエリでは items は空配列");
    assert_eq!(obj["vector_search_used"], false, "vector_search_used は false");
}