sse_integration.rs•6.24 kB
/// Basic integration tests for SSE MCP server
/// These tests verify SSE message format and protocol compliance without requiring a running server
use serde_json::{json, Value};
/// Test SSE endpoint format
#[tokio::test]
async fn test_sse_endpoint_format() {
// SSE endpoint should be /sse
let sse_endpoint = "/sse";
assert_eq!(sse_endpoint, "/sse");
// Message endpoint should be /message
let message_endpoint = "/message";
assert_eq!(message_endpoint, "/message");
}
/// Test SSE connection setup
#[tokio::test]
async fn test_sse_connection_setup() {
// SSE connections use EventSource on the client
// The server should accept GET requests to /sse
let url = "http://localhost:8000/sse";
assert!(url.starts_with("http://"));
assert!(url.ends_with("/sse"));
}
/// Test SSE message format
#[tokio::test]
async fn test_sse_message_format() {
// SSE messages should be in the format:
// event: message
// data: {"jsonrpc":"2.0", ...}
let message = json!({
"jsonrpc": "2.0",
"id": 1,
"method": "initialize",
"params": {
"protocolVersion": "2024-11-05",
"capabilities": {},
"clientInfo": {
"name": "test-client",
"version": "1.0.0"
}
}
});
// Verify message structure
assert_eq!(message["jsonrpc"], "2.0");
assert_eq!(message["method"], "initialize");
assert!(message["params"].is_object());
}
/// Test POST message to SSE server
#[tokio::test]
async fn test_sse_post_message_format() {
// Clients send messages via POST to /message endpoint
let message = json!({
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "run_js",
"arguments": {
"code": "1 + 1",
"heap": "test-heap"
}
}
});
assert_eq!(message["jsonrpc"], "2.0");
assert_eq!(message["method"], "tools/call");
assert_eq!(message["params"]["name"], "run_js");
}
/// Test MCP initialize message for SSE
#[tokio::test]
async fn test_sse_mcp_initialize() {
let initialize_request = json!({
"jsonrpc": "2.0",
"id": 1,
"method": "initialize",
"params": {
"protocolVersion": "2024-11-05",
"capabilities": {},
"clientInfo": {
"name": "sse-test-client",
"version": "1.0.0"
}
}
});
// Verify the request is properly formatted JSON-RPC
assert_eq!(initialize_request["jsonrpc"], "2.0");
assert_eq!(initialize_request["method"], "initialize");
assert!(initialize_request["params"].is_object());
assert_eq!(initialize_request["params"]["clientInfo"]["name"], "sse-test-client");
}
/// Test MCP tool call format for SSE
#[tokio::test]
async fn test_sse_mcp_tool_call_format() {
let tool_call_request = json!({
"jsonrpc": "2.0",
"id": 2,
"method": "tools/call",
"params": {
"name": "run_js",
"arguments": {
"code": "console.log('Hello from SSE')",
"heap": "sse-test-heap"
}
}
});
// Verify the request is properly formatted
assert_eq!(tool_call_request["jsonrpc"], "2.0");
assert_eq!(tool_call_request["method"], "tools/call");
assert_eq!(tool_call_request["params"]["name"], "run_js");
assert!(tool_call_request["params"]["arguments"].is_object());
}
/// Test JavaScript execution scenarios for SSE
#[tokio::test]
async fn test_sse_javascript_execution_scenarios() {
// Test simple arithmetic
let code1 = "2 + 2";
assert!(!code1.is_empty());
// Test variable assignment with persistence
let code2 = "let x = 10; x";
assert!(code2.contains("let"));
// Test accessing previously set variable
let code3 = "x * 2";
assert!(!code3.is_empty());
// All test code snippets are valid
assert!(true);
}
/// Test heap storage naming for SSE
#[tokio::test]
async fn test_sse_heap_naming() {
let heap_names = vec![
"sse-test-heap",
"sse-session-123",
"sse-calculation-workspace",
];
// Verify heap names are valid strings
for name in heap_names {
assert!(!name.is_empty());
assert!(!name.contains('/')); // No path separators
assert!(name.starts_with("sse-") || name.contains("sse"));
}
}
/// Test error handling for invalid JavaScript in SSE
#[tokio::test]
async fn test_sse_invalid_javascript_handling() {
// Examples of invalid JavaScript that should be caught
let invalid_codes = vec![
"this is not javascript",
"let y = ;",
"undefined.nonexistent()",
];
for code in invalid_codes {
// These should be handled gracefully by the server
let request = json!({
"code": code,
"heap": "sse-test-heap"
});
assert!(request.is_object());
}
}
/// Test SSE keep-alive configuration
#[tokio::test]
async fn test_sse_keepalive_config() {
// SSE server should have keep-alive configured (15 seconds based on implementation)
let keep_alive_seconds = 15;
assert_eq!(keep_alive_seconds, 15);
assert!(keep_alive_seconds > 0);
}
/// Test JSON-RPC error response format for SSE
#[tokio::test]
async fn test_sse_jsonrpc_error_format() {
let error_response = json!({
"jsonrpc": "2.0",
"id": 1,
"error": {
"code": -32600,
"message": "Invalid Request"
}
});
assert_eq!(error_response["jsonrpc"], "2.0");
assert!(error_response["error"].is_object());
assert!(error_response["error"]["code"].is_number());
assert!(error_response["error"]["message"].is_string());
}
/// Test SSE server configuration
#[tokio::test]
async fn test_sse_server_config() {
// Test that SSE server config parameters are valid
let bind_address = "0.0.0.0:8000";
let sse_path = "/sse";
let post_path = "/message";
assert!(bind_address.contains(":"));
assert!(sse_path.starts_with("/"));
assert!(post_path.starts_with("/"));
assert_ne!(sse_path, post_path);
}