codex-memory 3.0.15

A simple memory storage service with MCP interface for Claude Desktop
Documentation
use serde_json::json;

// We need to test the transport module's JsonRpcMessage parsing
#[test]
fn test_jsonrpc_request_parsing() {
    let request_json = json!({
        "jsonrpc": "2.0",
        "method": "tools/call",
        "params": {
            "name": "store_memory",
            "arguments": {
                "content": "test"
            }
        },
        "id": 1
    });

    // Verify the JSON structure is valid
    assert_eq!(request_json["jsonrpc"], "2.0");
    assert_eq!(request_json["method"], "tools/call");
    assert_eq!(request_json["id"], 1);
}

#[test]
fn test_jsonrpc_response_format() {
    let response = json!({
        "jsonrpc": "2.0",
        "result": {
            "success": true
        },
        "id": 1
    });

    // Verify response structure
    assert_eq!(response["jsonrpc"], "2.0");
    assert!(response["result"].is_object());
    assert_eq!(response["id"], 1);
}

#[test]
fn test_jsonrpc_error_format() {
    let error_response = json!({
        "jsonrpc": "2.0",
        "error": {
            "code": -32601,
            "message": "Method not found",
            "data": null
        },
        "id": 1
    });

    // Verify error structure
    assert_eq!(error_response["jsonrpc"], "2.0");
    assert_eq!(error_response["error"]["code"], -32601);
    assert_eq!(error_response["error"]["message"], "Method not found");
}

#[test]
fn test_jsonrpc_batch_request() {
    let batch = json!([
        {
            "jsonrpc": "2.0",
            "method": "tools/list",
            "id": 1
        },
        {
            "jsonrpc": "2.0",
            "method": "tools/call",
            "params": {
                "name": "get_statistics",
                "arguments": {}
            },
            "id": 2
        }
    ]);

    // Verify batch structure
    assert!(batch.is_array());
    let array = batch.as_array().unwrap();
    assert_eq!(array.len(), 2);
    assert_eq!(array[0]["method"], "tools/list");
    assert_eq!(array[1]["method"], "tools/call");
}

#[test]
fn test_content_length_header_parsing() {
    let header = "Content-Length: 123\r\n\r\n";

    // Parse content length
    let parts: Vec<&str> = header.split(": ").collect();
    assert_eq!(parts[0], "Content-Length");

    let length_str = parts[1].trim();
    let length: usize = length_str.parse().unwrap();
    assert_eq!(length, 123);
}

#[test]
fn test_message_framing() {
    let message = json!({
        "jsonrpc": "2.0",
        "method": "test",
        "id": 1
    });

    let json_str = message.to_string();
    let content_length = json_str.len();

    let framed = format!("Content-Length: {}\r\n\r\n{}", content_length, json_str);

    // Verify framing
    assert!(framed.starts_with("Content-Length: "));
    assert!(framed.contains("\r\n\r\n"));
    assert!(framed.ends_with(&json_str));
}

#[test]
fn test_notification_format() {
    // Notifications don't have an id field
    let notification = json!({
        "jsonrpc": "2.0",
        "method": "notification/test",
        "params": {
            "data": "test"
        }
    });

    // Verify notification structure
    assert_eq!(notification["jsonrpc"], "2.0");
    assert!(notification["method"].is_string());
    assert!(notification.get("id").is_none());
}

// Search-specific MCP transport tests
#[test]
fn test_search_memory_jsonrpc_request() {
    let search_request = json!({
        "jsonrpc": "2.0",
        "method": "tools/call",
        "params": {
            "name": "search_memory",
            "arguments": {
                "query": "rust programming",
                "similarity_threshold": 0.8,
                "max_results": 5,
                "search_strategy": "hybrid",
                "tag_filter": ["programming", "rust"]
            }
        },
        "id": 42
    });

    // Verify request structure
    assert_eq!(search_request["jsonrpc"], "2.0");
    assert_eq!(search_request["method"], "tools/call");
    assert_eq!(search_request["params"]["name"], "search_memory");
    assert_eq!(
        search_request["params"]["arguments"]["query"],
        "rust programming"
    );
    assert_eq!(
        search_request["params"]["arguments"]["similarity_threshold"],
        0.8
    );
    assert_eq!(search_request["params"]["arguments"]["max_results"], 5);
    assert_eq!(
        search_request["params"]["arguments"]["search_strategy"],
        "hybrid"
    );
    assert!(search_request["params"]["arguments"]["tag_filter"].is_array());
    assert_eq!(search_request["id"], 42);
}

#[test]
fn test_search_memory_minimal_request() {
    let minimal_request = json!({
        "jsonrpc": "2.0",
        "method": "tools/call",
        "params": {
            "name": "search_memory",
            "arguments": {
                "query": "test query"
            }
        },
        "id": 1
    });

    // Verify minimal valid request
    assert_eq!(
        minimal_request["params"]["arguments"]["query"],
        "test query"
    );
    assert!(minimal_request["params"]["arguments"]["tag_filter"].is_null());
    assert!(minimal_request["params"]["arguments"]["similarity_threshold"].is_null());
}

#[test]
fn test_search_memory_response_format() {
    let search_response = json!({
        "jsonrpc": "2.0",
        "result": {
            "results": [
                {
                    "id": "123e4567-e89b-12d3-a456-426614174000",
                    "content": "Test memory content",
                    "context": "Test context",
                    "summary": "Test summary",
                    "tags": ["test", "memory"],
                    "tag_similarity": 0.85,
                    "content_similarity": 0.92,
                    "combined_score": 0.89,
                    "semantic_cluster": 1,
                    "created_at": "2025-01-01T00:00:00Z",
                    "updated_at": "2025-01-01T00:00:00Z",
                    "chunk_index": null,
                    "total_chunks": null,
                    "parent_id": null
                }
            ],
            "search_metadata": {
                "query": "test query",
                "total_results": 1,
                "search_strategy": "hybrid",
                "similarity_threshold": 0.7,
                "max_results": 10,
                "tag_filter": null,
                "use_tag_embedding": true,
                "use_content_embedding": true,
                "boost_recent": false,
                "tag_weight": 0.4,
                "content_weight": 0.6,
                "search_time_ms": 125
            }
        },
        "id": 1
    });

    // Verify response structure
    assert_eq!(search_response["jsonrpc"], "2.0");
    assert!(search_response["result"].is_object());
    assert!(search_response["result"]["results"].is_array());
    assert!(search_response["result"]["search_metadata"].is_object());

    // Verify result structure
    let first_result = &search_response["result"]["results"][0];
    assert!(first_result["id"].is_string());
    assert!(first_result["content"].is_string());
    assert!(first_result["tag_similarity"].is_number());
    assert!(first_result["content_similarity"].is_number());
    assert!(first_result["combined_score"].is_number());

    // Verify metadata structure
    let metadata = &search_response["result"]["search_metadata"];
    assert!(metadata["query"].is_string());
    assert!(metadata["total_results"].is_number());
    assert!(metadata["search_strategy"].is_string());
    assert!(metadata["search_time_ms"].is_number());
}

#[test]
fn test_search_memory_error_responses() {
    // Missing query parameter error
    let missing_query_error = json!({
        "jsonrpc": "2.0",
        "error": {
            "code": -32602,
            "message": "Invalid params",
            "data": "Missing query parameter"
        },
        "id": 1
    });

    assert_eq!(missing_query_error["error"]["code"], -32602);
    assert!(missing_query_error["error"]["message"].is_string());

    // Unknown search strategy error
    let invalid_strategy_error = json!({
        "jsonrpc": "2.0",
        "error": {
            "code": -32602,
            "message": "Invalid params",
            "data": "Unknown search strategy: invalid_strategy"
        },
        "id": 1
    });

    assert_eq!(invalid_strategy_error["error"]["code"], -32602);
}

#[test]
fn test_search_empty_results_response() {
    let empty_response = json!({
        "jsonrpc": "2.0",
        "result": {
            "results": [],
            "search_metadata": {
                "query": "no matches query",
                "total_results": 0,
                "search_strategy": "hybrid",
                "similarity_threshold": 0.9,
                "max_results": 10,
                "tag_filter": null,
                "search_time_ms": 15
            }
        },
        "id": 1
    });

    // Verify empty results structure
    assert!(empty_response["result"]["results"].is_array());
    assert_eq!(
        empty_response["result"]["results"]
            .as_array()
            .unwrap()
            .len(),
        0
    );
    assert_eq!(
        empty_response["result"]["search_metadata"]["total_results"],
        0
    );
    assert!(empty_response["result"]["search_metadata"]["search_time_ms"].is_number());
}