pulseengine_mcp_auth/session/
mod.rs1pub mod session_manager;
7
8pub use session_manager::{
9 MemorySessionStorage, Session, SessionConfig, SessionError, SessionManager, SessionStats,
10 SessionStorage,
11};
12
13#[cfg(test)]
14mod tests {
15 use super::*;
16 use crate::AuthContext;
17 use crate::models::Role;
18 use std::sync::Arc;
19
20 #[test]
21 fn test_session_module_exports() {
22 let config = SessionConfig::default();
25 assert!(config.default_duration > chrono::Duration::zero());
26 assert!(config.enable_jwt);
27
28 let _storage = MemorySessionStorage::new();
29 let _stats = SessionStats {
32 total_sessions: 0,
33 active_sessions: 0,
34 expired_sessions: 0,
35 };
36 }
37
38 #[tokio::test]
39 async fn test_session_manager_integration() {
40 let config = SessionConfig {
41 default_duration: chrono::Duration::hours(1),
42 enable_jwt: true,
43 ..Default::default()
44 };
45
46 let storage = Arc::new(MemorySessionStorage::new());
47 let manager = SessionManager::new(config, storage);
48
49 let auth_context = AuthContext {
50 user_id: Some("test-user".to_string()),
51 roles: vec![Role::Operator],
52 api_key_id: Some("test-key".to_string()),
53 permissions: vec!["session:create".to_string()],
54 };
55
56 let session = manager
58 .create_session(
59 "test-user".to_string(),
60 auth_context,
61 None, Some("127.0.0.1".to_string()), Some("test-agent".to_string()), )
65 .await;
66 assert!(session.is_ok());
67
68 let (session, _jwt_token) = session.unwrap();
69 assert_eq!(session.user_id, "test-user");
70 assert!(!session.session_id.is_empty());
71 assert!(session.expires_at > chrono::Utc::now());
72
73 let retrieved = manager.get_session(&session.session_id).await;
75 assert!(retrieved.is_ok());
76
77 let retrieved = retrieved.unwrap();
78 assert_eq!(retrieved.session_id, session.session_id);
79 assert_eq!(retrieved.user_id, session.user_id);
80 }
81
82 #[tokio::test]
83 async fn test_session_storage_types() {
84 let memory_storage = MemorySessionStorage::new();
86
87 let auth_context = AuthContext {
88 user_id: Some("test-user".to_string()),
89 roles: vec![Role::Operator],
90 api_key_id: Some("test-key".to_string()),
91 permissions: vec!["session:create".to_string()],
92 };
93
94 let session = Session {
95 session_id: "test-session".to_string(),
96 user_id: "test-user".to_string(),
97 auth_context,
98 created_at: chrono::Utc::now(),
99 expires_at: chrono::Utc::now() + chrono::Duration::hours(1),
100 last_accessed: chrono::Utc::now(),
101 client_ip: Some("127.0.0.1".to_string()),
102 user_agent: Some("test-agent".to_string()),
103 metadata: std::collections::HashMap::new(),
104 is_active: true,
105 refresh_token: None,
106 };
107
108 let result = memory_storage.store_session(&session).await;
110 assert!(result.is_ok());
111
112 let retrieved = memory_storage.get_session(&session.session_id).await;
113 assert!(retrieved.is_ok());
114
115 let retrieved = retrieved.unwrap();
116 assert!(retrieved.is_some());
117 let retrieved = retrieved.unwrap();
118 assert_eq!(retrieved.session_id, session.session_id);
119 assert_eq!(retrieved.user_id, session.user_id);
120 }
121
122 #[test]
123 fn test_session_error_types() {
124 let errors = vec![
125 SessionError::SessionNotFound {
126 session_id: "test".to_string(),
127 },
128 SessionError::SessionExpired {
129 session_id: "test".to_string(),
130 },
131 SessionError::SessionInvalid {
132 reason: "test".to_string(),
133 },
134 SessionError::MaxSessionsExceeded {
135 user_id: "test".to_string(),
136 },
137 SessionError::CreationFailed {
138 reason: "test".to_string(),
139 },
140 SessionError::StorageError("test".to_string()),
141 SessionError::InvalidToken,
142 ];
143
144 for error in errors {
145 let error_string = error.to_string();
146 assert!(!error_string.is_empty());
147 assert!(error_string.len() > 5);
148 }
149 }
150
151 #[test]
152 fn test_session_config_defaults() {
153 let config = SessionConfig::default();
154
155 assert!(config.default_duration > chrono::Duration::zero());
156 assert!(config.default_duration <= chrono::Duration::hours(24)); assert!(config.enable_jwt);
158 }
160
161 #[tokio::test]
162 async fn test_session_lifecycle() {
163 let config = SessionConfig::default();
164 let storage = Arc::new(MemorySessionStorage::new());
165 let manager = SessionManager::new(config, storage);
166
167 let auth_context = AuthContext {
168 user_id: Some("lifecycle-user".to_string()),
169 roles: vec![Role::Operator],
170 api_key_id: Some("lifecycle-key".to_string()),
171 permissions: vec!["session:create".to_string()],
172 };
173
174 let session = manager
176 .create_session(
177 "lifecycle-user".to_string(),
178 auth_context,
179 Some(chrono::Duration::minutes(1)), Some("127.0.0.1".to_string()), Some("test-agent".to_string()), )
183 .await
184 .unwrap();
185 let (session, _jwt_token) = session;
186 let session_id = session.session_id.clone();
187
188 let retrieved = manager.get_session(&session_id).await.unwrap();
190 assert!(retrieved.is_active);
191 assert!(retrieved.expires_at > chrono::Utc::now());
192
193 if let Some(refresh_token) = &session.refresh_token {
195 let refreshed = manager.refresh_session(&session_id, refresh_token).await;
196 assert!(refreshed.is_ok());
197 let (refreshed_session, _new_jwt) = refreshed.unwrap();
198 assert!(refreshed_session.expires_at > retrieved.expires_at);
199 }
200
201 let terminated = manager.terminate_session(&session_id).await;
203 assert!(terminated.is_ok());
204
205 let after_revoke = manager.get_session(&session_id).await;
207 assert!(after_revoke.is_err() || !after_revoke.unwrap().is_active);
209 }
210}