#![allow(deprecated)]
use std::sync::Arc;
use std::time::Duration;
use actix_web::{App, test, web};
use rmcp::transport::streamable_http_server::session::local::LocalSessionManager;
#[cfg(feature = "transport-sse")]
use rmcp_actix_web::transport::SseService;
use rmcp_actix_web::transport::StreamableHttpService;
mod common;
use common::calculator::Calculator;
#[actix_web::test]
#[cfg(feature = "transport-sse")]
async fn test_sse_service_scope_composition() {
let sse_service = SseService::builder()
.service_factory(Arc::new(|| Ok(Calculator::new())))
.sse_path("/sse".to_string())
.post_path("/message".to_string())
.build();
let app = test::init_service(
App::new().service(web::scope("/api/v1/mcp").service(sse_service.scope())),
)
.await;
let req = test::TestRequest::get()
.uri("/api/v1/mcp/sse")
.insert_header(("mcp-session-id", "test-session"))
.to_request();
let resp = test::call_service(&app, req).await;
assert_eq!(resp.status(), 200);
assert_eq!(
resp.headers().get("content-type").unwrap(),
"text/event-stream"
);
}
#[actix_web::test]
async fn test_streamable_http_service_scope_composition() {
let http_service = StreamableHttpService::builder()
.service_factory(Arc::new(|| Ok(Calculator::new())))
.session_manager(Arc::new(LocalSessionManager::default()))
.stateful_mode(true)
.build();
let app = test::init_service(
App::new().service(web::scope("/api/v2/mcp").service(http_service.scope())),
)
.await;
let req = test::TestRequest::post()
.uri("/api/v2/mcp/")
.insert_header(("content-type", "application/json"))
.insert_header(("accept", "application/json, text/event-stream"))
.set_json(serde_json::json!({
"jsonrpc": "2.0",
"id": 1,
"method": "initialize",
"params": {
"protocolVersion": "2024-11-05",
"capabilities": {},
"clientInfo": {
"name": "test-client",
"version": "1.0.0"
}
}
}))
.to_request();
let resp = test::call_service(&app, req).await;
assert!(resp.status().is_success() || resp.status().is_client_error()); }
#[actix_web::test]
#[cfg(feature = "transport-sse")]
async fn test_multiple_services_composition() {
let sse_service = SseService::builder()
.service_factory(Arc::new(|| Ok(Calculator::new())))
.sse_path("/sse".to_string())
.post_path("/message".to_string())
.build();
let http_service = StreamableHttpService::builder()
.service_factory(Arc::new(|| Ok(Calculator::new())))
.session_manager(Arc::new(LocalSessionManager::default()))
.stateful_mode(true)
.build();
let app = test::init_service(
App::new()
.service(web::scope("/sse-calc").service(sse_service.scope()))
.service(web::scope("/http-calc").service(http_service.scope())),
)
.await;
let sse_req = test::TestRequest::get()
.uri("/sse-calc/sse")
.insert_header(("mcp-session-id", "test-session"))
.to_request();
let sse_resp = test::call_service(&app, sse_req).await;
assert_eq!(sse_resp.status(), 200);
let http_req = test::TestRequest::post()
.uri("/http-calc/")
.insert_header(("content-type", "application/json"))
.insert_header(("accept", "application/json, text/event-stream"))
.set_json(serde_json::json!({
"jsonrpc": "2.0",
"id": 1,
"method": "initialize",
"params": {
"protocolVersion": "2024-11-05",
"capabilities": {},
"clientInfo": {
"name": "test-client",
"version": "1.0.0"
}
}
}))
.to_request();
let http_resp = test::call_service(&app, http_req).await;
assert!(http_resp.status().is_success() || http_resp.status().is_client_error());
}
#[actix_web::test]
#[cfg(feature = "transport-sse")]
async fn test_nested_scope_composition() {
let sse_service = SseService::builder()
.service_factory(Arc::new(|| Ok(Calculator::new())))
.sse_path("/sse".to_string())
.post_path("/message".to_string())
.sse_keep_alive(Duration::from_secs(30))
.build();
let app = test::init_service(App::new().service(web::scope("/api").service(
web::scope("/v1").service(
web::scope("/services").service(web::scope("/mcp").service(sse_service.scope())),
),
)))
.await;
let req = test::TestRequest::get()
.uri("/api/v1/services/mcp/sse")
.insert_header(("mcp-session-id", "test-session"))
.to_request();
let resp = test::call_service(&app, req).await;
assert_eq!(resp.status(), 200);
assert_eq!(
resp.headers().get("content-type").unwrap(),
"text/event-stream"
);
}