1use crate::config::StorageBackend;
7use crate::database::{create_database, VirtualDatabase};
8use crate::Result;
9use mockforge_core::intelligent_behavior::session::SessionManager;
10use std::collections::HashMap;
11use std::sync::Arc;
12use tokio::sync::RwLock;
13
14pub struct SessionDataManager {
19 pub session_manager: Arc<SessionManager>,
21 storage_backend: StorageBackend,
23 session_databases: Arc<RwLock<HashMap<String, Arc<dyn VirtualDatabase + Send + Sync>>>>,
25}
26
27impl SessionDataManager {
28 pub fn new(session_manager: Arc<SessionManager>, storage_backend: StorageBackend) -> Self {
30 Self {
31 session_manager,
32 storage_backend,
33 session_databases: Arc::new(RwLock::new(HashMap::new())),
34 }
35 }
36
37 pub async fn get_session_database(
42 &self,
43 session_id: &str,
44 ) -> Result<Arc<dyn VirtualDatabase + Send + Sync>> {
45 let session_state = self.session_manager.get_session(session_id).await;
47 if session_state.is_none() {
48 return Err(crate::Error::generic(format!("Session '{}' not found", session_id)));
49 }
50
51 let databases = self.session_databases.read().await;
53 if let Some(db) = databases.get(session_id) {
54 return Ok(Arc::clone(db));
55 }
56 drop(databases);
57
58 let db_arc = create_database(&StorageBackend::Memory).await?;
61 let db_clone = Arc::clone(&db_arc);
63
64 let mut databases = self.session_databases.write().await;
66 databases.insert(session_id.to_string(), db_arc);
67
68 Ok(db_clone)
69 }
70
71 pub async fn cleanup_session_database(&self, session_id: &str) -> Result<()> {
73 let mut databases = self.session_databases.write().await;
74 databases.remove(session_id);
75 Ok(())
77 }
78
79 pub async fn cleanup_expired_sessions(&self) -> Result<usize> {
81 let expired_count = self.session_manager.cleanup_expired_sessions().await;
83
84 let active_sessions = self.session_manager.list_sessions().await;
86 let active_set: std::collections::HashSet<String> = active_sessions.into_iter().collect();
87
88 let mut databases = self.session_databases.write().await;
90 let mut removed = 0;
91 let expired_db_sessions: Vec<String> = databases
92 .keys()
93 .filter(|session_id| !active_set.contains(*session_id))
94 .cloned()
95 .collect();
96
97 for session_id in expired_db_sessions {
98 databases.remove(&session_id);
99 removed += 1;
100 }
101
102 Ok(removed)
103 }
104
105 pub fn session_manager(&self) -> &Arc<SessionManager> {
107 &self.session_manager
108 }
109
110 pub async fn get_session_state(
112 &self,
113 session_id: &str,
114 ) -> Option<mockforge_core::intelligent_behavior::types::SessionState> {
115 self.session_manager.get_session(session_id).await
116 }
117
118 pub async fn update_session_state(
120 &self,
121 session_id: &str,
122 state: mockforge_core::intelligent_behavior::types::SessionState,
123 ) -> Result<()> {
124 self.session_manager.update_session(session_id, state).await
125 }
126}
127
128#[cfg(test)]
129mod tests {
130 use super::*;
131 use mockforge_core::intelligent_behavior::session::SessionTracking;
132
133 fn create_test_session_manager() -> Arc<SessionManager> {
134 let config = SessionTracking::default();
135 Arc::new(SessionManager::new(config, 3600))
136 }
137
138 #[tokio::test]
139 async fn test_session_data_manager_new() {
140 let session_manager = create_test_session_manager();
141 let manager = SessionDataManager::new(session_manager.clone(), StorageBackend::Memory);
142
143 assert!(Arc::ptr_eq(&manager.session_manager, &session_manager));
144 }
145
146 #[tokio::test]
147 async fn test_get_session_database_no_session() {
148 let session_manager = create_test_session_manager();
149 let manager = SessionDataManager::new(session_manager, StorageBackend::Memory);
150
151 let result = manager.get_session_database("nonexistent-session").await;
152 assert!(result.is_err());
153 match result {
154 Err(err) => {
155 assert!(err.to_string().contains("Session"));
156 assert!(err.to_string().contains("not found"));
157 }
158 Ok(_) => panic!("Expected an error"),
159 }
160 }
161
162 #[tokio::test]
163 async fn test_get_session_database_creates_new() {
164 let session_manager = create_test_session_manager();
165
166 let _ = session_manager.get_or_create_session(Some("test-session".to_string())).await;
168
169 let manager = SessionDataManager::new(session_manager, StorageBackend::Memory);
170 let result = manager.get_session_database("test-session").await;
171
172 assert!(result.is_ok());
173 }
174
175 #[tokio::test]
176 async fn test_get_session_database_returns_same() {
177 let session_manager = create_test_session_manager();
178
179 let _ = session_manager.get_or_create_session(Some("test-session".to_string())).await;
181
182 let manager = SessionDataManager::new(session_manager, StorageBackend::Memory);
183
184 let db1 = manager.get_session_database("test-session").await.unwrap();
186 let db2 = manager.get_session_database("test-session").await.unwrap();
187
188 assert!(Arc::ptr_eq(&db1, &db2));
190 }
191
192 #[tokio::test]
193 async fn test_cleanup_session_database() {
194 let session_manager = create_test_session_manager();
195
196 let _ = session_manager.get_or_create_session(Some("test-session".to_string())).await;
198
199 let manager = SessionDataManager::new(session_manager, StorageBackend::Memory);
200
201 let _db = manager.get_session_database("test-session").await.unwrap();
203
204 let result = manager.cleanup_session_database("test-session").await;
206 assert!(result.is_ok());
207 }
208
209 #[tokio::test]
210 async fn test_cleanup_nonexistent_session() {
211 let session_manager = create_test_session_manager();
212 let manager = SessionDataManager::new(session_manager, StorageBackend::Memory);
213
214 let result = manager.cleanup_session_database("nonexistent").await;
216 assert!(result.is_ok());
217 }
218
219 #[tokio::test]
220 async fn test_session_manager_getter() {
221 let session_manager = create_test_session_manager();
222 let manager = SessionDataManager::new(session_manager.clone(), StorageBackend::Memory);
223
224 assert!(Arc::ptr_eq(manager.session_manager(), &session_manager));
225 }
226
227 #[tokio::test]
228 async fn test_get_session_state_exists() {
229 let session_manager = create_test_session_manager();
230
231 let _ = session_manager.get_or_create_session(Some("test-session".to_string())).await;
233
234 let manager = SessionDataManager::new(session_manager, StorageBackend::Memory);
235 let state = manager.get_session_state("test-session").await;
236
237 assert!(state.is_some());
238 }
239
240 #[tokio::test]
241 async fn test_get_session_state_not_exists() {
242 let session_manager = create_test_session_manager();
243 let manager = SessionDataManager::new(session_manager, StorageBackend::Memory);
244
245 let state = manager.get_session_state("nonexistent").await;
246 assert!(state.is_none());
247 }
248
249 #[tokio::test]
250 async fn test_multiple_sessions_isolated() {
251 let session_manager = create_test_session_manager();
252
253 let _ = session_manager.get_or_create_session(Some("session-1".to_string())).await;
255 let _ = session_manager.get_or_create_session(Some("session-2".to_string())).await;
256
257 let manager = SessionDataManager::new(session_manager, StorageBackend::Memory);
258
259 let db1 = manager.get_session_database("session-1").await.unwrap();
260 let db2 = manager.get_session_database("session-2").await.unwrap();
261
262 assert!(!Arc::ptr_eq(&db1, &db2));
264 }
265
266 #[tokio::test]
267 async fn test_cleanup_expired_sessions() {
268 let session_manager = create_test_session_manager();
269 let manager = SessionDataManager::new(session_manager, StorageBackend::Memory);
270
271 let result = manager.cleanup_expired_sessions().await;
272 assert!(result.is_ok());
273 }
274}