use std::time::Duration;
use dk_engine::workspace::session_manager::WorkspaceManager;
use dk_engine::workspace::session_workspace::{SessionWorkspace, WorkspaceMode};
use sqlx::PgPool;
use uuid::Uuid;
fn test_manager() -> WorkspaceManager {
let db = PgPool::connect_lazy("postgres://localhost/nonexistent").unwrap();
WorkspaceManager::new(db)
}
fn make_workspace(session_id: Uuid) -> SessionWorkspace {
SessionWorkspace::new_test(
session_id,
Uuid::new_v4(),
"test-agent".to_string(),
"test intent".to_string(),
"abc123".to_string(),
WorkspaceMode::Ephemeral,
)
}
#[tokio::test(start_paused = true)]
async fn test_gc_expires_idle_sessions() {
let mgr = test_manager();
let session_id = Uuid::new_v4();
let ws = make_workspace(session_id);
mgr.insert_test_workspace(ws);
assert_eq!(mgr.total_active(), 1);
tokio::time::advance(Duration::from_secs(31 * 60)).await;
let expired = mgr.gc_expired_sessions(
Duration::from_secs(30 * 60), Duration::from_secs(4 * 3600), );
assert_eq!(expired.len(), 1);
assert_eq!(expired[0], session_id);
assert_eq!(mgr.total_active(), 0, "workspace should be removed from map");
}
#[tokio::test(start_paused = true)]
async fn test_gc_preserves_active_sessions() {
let mgr = test_manager();
let session_id = Uuid::new_v4();
let ws = make_workspace(session_id);
mgr.insert_test_workspace(ws);
tokio::time::advance(Duration::from_secs(5 * 60)).await;
let expired = mgr.gc_expired_sessions(
Duration::from_secs(30 * 60),
Duration::from_secs(4 * 3600),
);
assert!(expired.is_empty(), "active session should not be expired");
assert_eq!(mgr.total_active(), 1, "workspace should remain in map");
}
#[tokio::test(start_paused = true)]
async fn test_gc_hard_max_ttl() {
let mgr = test_manager();
let session_id = Uuid::new_v4();
mgr.insert_test_workspace(make_workspace(session_id));
tokio::time::advance(Duration::from_secs(4 * 3600 + 1)).await;
if let Some(mut ws_ref) = mgr.get_workspace_mut(&session_id) {
ws_ref.touch();
}
let expired = mgr.gc_expired_sessions(
Duration::from_secs(30 * 60), Duration::from_secs(4 * 3600), );
assert_eq!(expired.len(), 1, "session should expire due to max_ttl despite recent activity");
assert_eq!(expired[0], session_id);
assert_eq!(mgr.total_active(), 0);
}
#[tokio::test(start_paused = true)]
async fn test_gc_mixed_sessions() {
let mgr = test_manager();
let idle_id = Uuid::new_v4();
let active_id = Uuid::new_v4();
mgr.insert_test_workspace(make_workspace(idle_id));
tokio::time::advance(Duration::from_secs(20 * 60)).await;
mgr.insert_test_workspace(make_workspace(active_id));
tokio::time::advance(Duration::from_secs(15 * 60)).await;
if let Some(mut ws) = mgr.get_workspace_mut(&active_id) {
ws.touch();
}
let expired = mgr.gc_expired_sessions(
Duration::from_secs(30 * 60),
Duration::from_secs(4 * 3600),
);
assert_eq!(expired.len(), 1, "only idle session should expire");
assert_eq!(expired[0], idle_id);
assert_eq!(mgr.total_active(), 1, "active session should remain");
assert!(mgr.get_workspace(&active_id).is_some());
}