mcp: evict expired transport sessions
This commit is contained in:
@@ -158,7 +158,10 @@ mod tests {
|
||||
use tokio::time::sleep;
|
||||
use tracing_subscriber::{filter::LevelFilter, fmt::MakeWriter, prelude::*};
|
||||
|
||||
use crate::{app::build_app, session::InMemorySessionStore};
|
||||
use crate::{
|
||||
app::build_app,
|
||||
session::{InMemorySessionStore, SharedSessionStore, TransportSessionStore},
|
||||
};
|
||||
|
||||
fn test_workspace_id() -> WorkspaceId {
|
||||
WorkspaceId::new("ws_default")
|
||||
@@ -222,6 +225,22 @@ mod tests {
|
||||
refresh_interval: Duration,
|
||||
public_base_url: Option<String>,
|
||||
rate_limit_config: RequestRateLimitConfig,
|
||||
) -> axum::Router {
|
||||
build_test_app_with_store(
|
||||
registry,
|
||||
refresh_interval,
|
||||
public_base_url,
|
||||
rate_limit_config,
|
||||
std::sync::Arc::new(InMemorySessionStore::default()),
|
||||
)
|
||||
}
|
||||
|
||||
fn build_test_app_with_store(
|
||||
registry: PostgresRegistry,
|
||||
refresh_interval: Duration,
|
||||
public_base_url: Option<String>,
|
||||
rate_limit_config: RequestRateLimitConfig,
|
||||
sessions: SharedSessionStore,
|
||||
) -> axum::Router {
|
||||
build_app(
|
||||
registry,
|
||||
@@ -230,7 +249,7 @@ mod tests {
|
||||
SecretCrypto::new("test-master-key").unwrap(),
|
||||
RuntimeExecutor::new(),
|
||||
RequestRateLimiter::new(rate_limit_config),
|
||||
std::sync::Arc::new(InMemorySessionStore::default()),
|
||||
sessions,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -877,6 +896,57 @@ mod tests {
|
||||
);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn get_returns_not_found_for_expired_transport_session() {
|
||||
let registry = test_registry().await;
|
||||
publish_agent_with_bindings(®istry, "sales-expired-session", vec![]).await;
|
||||
let api_key = create_platform_api_key(
|
||||
®istry,
|
||||
"mcp-expired-session",
|
||||
&[PlatformApiKeyScope::Read],
|
||||
)
|
||||
.await;
|
||||
let session_store = Arc::new(InMemorySessionStore::default());
|
||||
let session_id = session_store
|
||||
.create(
|
||||
"2025-11-25",
|
||||
test_workspace_slug(),
|
||||
"sales-expired-session",
|
||||
OffsetDateTime::parse("2026-05-01T10:00:00Z", &Rfc3339).unwrap(),
|
||||
Some(OffsetDateTime::parse("2026-05-01T10:00:01Z", &Rfc3339).unwrap()),
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
session_store
|
||||
.mark_initialized(
|
||||
&session_id,
|
||||
OffsetDateTime::parse("2026-05-01T10:00:01Z", &Rfc3339).unwrap(),
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
let base_url = spawn_mcp_server(build_test_app_with_store(
|
||||
registry,
|
||||
Duration::from_millis(0),
|
||||
Some("https://crank.example.com".to_owned()),
|
||||
RequestRateLimitConfig::new(10_000, 10_000).unwrap(),
|
||||
session_store,
|
||||
))
|
||||
.await;
|
||||
let client = reqwest::Client::new();
|
||||
|
||||
let response = client
|
||||
.get(agent_mcp_url(&base_url, "sales-expired-session"))
|
||||
.header(header::ACCEPT, "text/event-stream")
|
||||
.header(header::AUTHORIZATION, format!("Bearer {api_key}"))
|
||||
.header("MCP-Session-Id", &session_id)
|
||||
.header("MCP-Protocol-Version", "2025-11-25")
|
||||
.send()
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(response.status(), reqwest::StatusCode::NOT_FOUND);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn get_requires_session_header() {
|
||||
let registry = test_registry().await;
|
||||
|
||||
Reference in New Issue
Block a user