#[cfg(feature = "sessions")]
mod tests {
use std::sync::Arc;
use std::time::Duration;
use bytes::Bytes;
use hyper::{HeaderMap, Method, Version};
use reinhardt_di::{DiError, Injectable, InjectionContext, SingletonScope};
use reinhardt_http::Request;
use reinhardt_middleware::session::{
OptionalSessionValue, SessionData, SessionStore, SessionValue, USER_ID_SESSION_KEY,
};
fn build_ctx_with_session(
store: Arc<SessionStore>,
session_cookie: Option<&str>,
) -> InjectionContext {
let mut headers = HeaderMap::new();
if let Some(cookie) = session_cookie {
headers.insert(
hyper::header::COOKIE,
hyper::header::HeaderValue::from_str(&format!("sessionid={cookie}")).unwrap(),
);
}
let request = Request::builder()
.method(Method::GET)
.uri("/test")
.version(Version::HTTP_11)
.headers(headers)
.body(Bytes::new())
.build()
.unwrap();
let singleton: Arc<SingletonScope> = Arc::new(SingletonScope::new());
singleton.set_arc(store);
let ctx = InjectionContext::builder(singleton).build();
ctx.set_request(request);
ctx
}
#[tokio::test]
async fn session_value_returns_stored_user_id() {
let store = Arc::new(SessionStore::new());
let mut session = SessionData::new(Duration::from_secs(3600));
session
.set(USER_ID_SESSION_KEY.to_string(), 123i64)
.unwrap();
let session_id = session.id.clone();
store.save(session);
let ctx = build_ctx_with_session(Arc::clone(&store), Some(&session_id));
let SessionValue(user_id) = SessionValue::<i64>::inject(&ctx)
.await
.expect("SessionValue should resolve when the key is present");
assert_eq!(user_id, 123);
}
#[tokio::test]
async fn session_value_fails_when_key_missing() {
let store = Arc::new(SessionStore::new());
let session = SessionData::new(Duration::from_secs(3600));
let session_id = session.id.clone();
store.save(session);
let ctx = build_ctx_with_session(Arc::clone(&store), Some(&session_id));
let err = SessionValue::<i64>::inject(&ctx)
.await
.expect_err("SessionValue must fail when the user-id key is absent");
assert!(
matches!(err, DiError::Authentication(_)),
"expected DiError::Authentication, got {err:?}"
);
}
#[tokio::test]
async fn optional_session_value_yields_none_when_session_missing() {
let store = Arc::new(SessionStore::new());
let ctx = build_ctx_with_session(store, None);
let OptionalSessionValue(maybe_id) = OptionalSessionValue::<i64>::inject(&ctx)
.await
.expect("OptionalSessionValue must never fail injection when session is absent");
assert_eq!(maybe_id, None);
}
#[tokio::test]
async fn optional_session_value_returns_some_when_key_present() {
let store = Arc::new(SessionStore::new());
let mut session = SessionData::new(Duration::from_secs(3600));
session.set(USER_ID_SESSION_KEY.to_string(), 99i64).unwrap();
let session_id = session.id.clone();
store.save(session);
let ctx = build_ctx_with_session(Arc::clone(&store), Some(&session_id));
let OptionalSessionValue(maybe_id) = OptionalSessionValue::<i64>::inject(&ctx)
.await
.expect("OptionalSessionValue should resolve when the session carries the key");
assert_eq!(maybe_id, Some(99));
}
#[tokio::test]
async fn optional_session_value_yields_none_when_key_missing() {
let store = Arc::new(SessionStore::new());
let session = SessionData::new(Duration::from_secs(3600));
let session_id = session.id.clone();
store.save(session);
let ctx = build_ctx_with_session(Arc::clone(&store), Some(&session_id));
let OptionalSessionValue(maybe_id) = OptionalSessionValue::<i64>::inject(&ctx)
.await
.expect("OptionalSessionValue must succeed when the key is absent");
assert_eq!(maybe_id, None);
}
}