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