0e8f1ca03a
Добавить структурированные журналы, метрики, трассировку и безопасный канал критических ошибок. Усилить границы рантайма, тесты, проверку зависимостей и сценарии развёртывания.
111 lines
3.1 KiB
Rust
111 lines
3.1 KiB
Rust
use crank_community_mcp::session::{
|
|
InMemorySessionStore, SessionStoreError, TransportSessionStore,
|
|
};
|
|
use time::format_description::well_known::Rfc3339;
|
|
|
|
fn timestamp(value: &str) -> time::OffsetDateTime {
|
|
time::OffsetDateTime::parse(value, &Rfc3339).unwrap()
|
|
}
|
|
|
|
#[tokio::test]
|
|
async fn creates_and_reads_transport_sessions() {
|
|
let store = InMemorySessionStore::default();
|
|
let created_at = timestamp("2026-05-01T10:00:00Z");
|
|
|
|
let session_id = store
|
|
.create("2025-11-25", "default", "sales", false, created_at, None)
|
|
.await
|
|
.unwrap();
|
|
let session = store.get(&session_id).await.unwrap().unwrap();
|
|
|
|
assert_eq!(session.id, session_id);
|
|
assert_eq!(session.protocol_version, "2025-11-25");
|
|
assert_eq!(session.workspace_slug, "default");
|
|
assert_eq!(session.agent_slug, "sales");
|
|
assert!(!session.initialized);
|
|
assert!(!session.supports_elicitation);
|
|
assert_eq!(session.created_at, created_at);
|
|
assert_eq!(session.updated_at, created_at);
|
|
}
|
|
|
|
#[tokio::test]
|
|
async fn marks_transport_sessions_initialized() {
|
|
let store = InMemorySessionStore::default();
|
|
let created_at = timestamp("2026-05-01T10:00:00Z");
|
|
let initialized_at = timestamp("2026-05-01T10:00:05Z");
|
|
|
|
let session_id = store
|
|
.create("2025-11-25", "default", "sales", false, created_at, None)
|
|
.await
|
|
.unwrap();
|
|
|
|
assert!(
|
|
store
|
|
.mark_initialized(&session_id, initialized_at)
|
|
.await
|
|
.unwrap()
|
|
);
|
|
|
|
let session = store.get(&session_id).await.unwrap().unwrap();
|
|
assert!(session.initialized);
|
|
assert_eq!(session.updated_at, initialized_at);
|
|
}
|
|
|
|
#[tokio::test]
|
|
async fn drops_expired_in_memory_transport_sessions_on_read() {
|
|
let store = InMemorySessionStore::default();
|
|
let created_at = timestamp("2026-05-01T10:00:00Z");
|
|
let expires_at = timestamp("2026-05-01T10:00:01Z");
|
|
|
|
let session_id = store
|
|
.create(
|
|
"2025-11-25",
|
|
"default",
|
|
"sales",
|
|
false,
|
|
created_at,
|
|
Some(expires_at),
|
|
)
|
|
.await
|
|
.unwrap();
|
|
|
|
assert!(store.get(&session_id).await.unwrap().is_none());
|
|
}
|
|
|
|
#[tokio::test]
|
|
async fn cleanup_removes_only_expired_sessions() {
|
|
let store = InMemorySessionStore::default();
|
|
let now = time::OffsetDateTime::now_utc();
|
|
let expired = store
|
|
.create("2025-11-25", "default", "sales", false, now, Some(now))
|
|
.await
|
|
.unwrap();
|
|
let active = store
|
|
.create(
|
|
"2025-11-25",
|
|
"default",
|
|
"sales",
|
|
false,
|
|
now,
|
|
Some(now + time::Duration::hours(1)),
|
|
)
|
|
.await
|
|
.unwrap();
|
|
|
|
assert_eq!(store.cleanup_expired(now).await.unwrap(), 1);
|
|
assert!(store.get(&expired).await.unwrap().is_none());
|
|
assert!(store.get(&active).await.unwrap().is_some());
|
|
}
|
|
|
|
#[test]
|
|
fn formats_transport_session_store_error() {
|
|
let error = SessionStoreError {
|
|
details: "postgres is unavailable".to_owned(),
|
|
};
|
|
|
|
assert_eq!(
|
|
error.to_string(),
|
|
"transport session store is unavailable: postgres is unavailable"
|
|
);
|
|
}
|