use super::super::*;
use super::CacheDirEnvGuard;
use crate::depgraph::SessionConfig;
fn session_under(worktree: &std::path::Path, journal: Option<&std::path::Path>) -> SessionConfig {
SessionConfig {
client_pid: std::process::id(),
working_dir: NormalizedPath::from(worktree),
log_file: None,
track_stats: false,
journal_path: journal.map(NormalizedPath::from),
profile: false,
private_env: Vec::new(),
owner_pids: Vec::new(),
}
}
#[tokio::test]
#[ignore] async fn release_drops_sessions_under_path_and_leaves_siblings() {
crate::test_support::test_timeout(async {
let cache_tmp = tempfile::tempdir().unwrap();
let _env = CacheDirEnvGuard::set(cache_tmp.path());
let endpoint = crate::ipc::unique_test_endpoint();
let cache_dir = NormalizedPath::new(cache_tmp.path());
let server = DaemonServer::bind_with_cache_dir(&endpoint, &cache_dir).unwrap();
let worktree_a = tempfile::tempdir().unwrap();
let worktree_b = tempfile::tempdir().unwrap();
let inside_a = worktree_a.path().join("target/debug");
std::fs::create_dir_all(&inside_a).unwrap();
let state = server.test_state();
let sid_root_a = state
.sessions
.create(session_under(worktree_a.path(), None));
let sid_inside_a = state.sessions.create(session_under(&inside_a, None));
let sid_b = state
.sessions
.create(session_under(worktree_b.path(), None));
assert_eq!(state.sessions.active_count(), 3);
let target = NormalizedPath::new(worktree_a.path());
let resp = super::super::handle_release_worktree_handles::handle_release_worktree_handles(
state, &target,
)
.await;
let Response::ReleaseWorktreeHandlesResult {
inspected,
released,
sessions_dropped,
unreleased,
} = resp
else {
panic!("expected ReleaseWorktreeHandlesResult, got: {resp:?}");
};
assert_eq!(inspected, 3, "should have looked at every active session");
assert_eq!(released, 2, "both sessions under worktree_a must drop");
assert!(
unreleased.is_empty(),
"no long-lived mmaps means nothing should fail to release; got {unreleased:?}"
);
assert_eq!(state.sessions.active_count(), 1, "sibling session survives");
assert!(
state.sessions.get(&sid_b).is_some(),
"session under worktree_b must still exist"
);
assert!(
state.sessions.get(&sid_root_a).is_none()
&& state.sessions.get(&sid_inside_a).is_none(),
"sessions under worktree_a must be gone"
);
let dropped: std::collections::HashSet<String> = sessions_dropped.into_iter().collect();
assert!(dropped.contains(&sid_root_a.to_string()));
assert!(dropped.contains(&sid_inside_a.to_string()));
})
.await;
}
#[tokio::test]
#[ignore] async fn release_refuses_to_release_cache_root() {
crate::test_support::test_timeout(async {
let cache_tmp = tempfile::tempdir().unwrap();
let _env = CacheDirEnvGuard::set(cache_tmp.path());
let endpoint = crate::ipc::unique_test_endpoint();
let cache_dir = NormalizedPath::new(cache_tmp.path());
let server = DaemonServer::bind_with_cache_dir(&endpoint, &cache_dir).unwrap();
let state = server.test_state();
let unrelated = tempfile::tempdir().unwrap();
let sid = state.sessions.create(session_under(unrelated.path(), None));
assert!(state.sessions.get(&sid).is_some());
let resp = super::super::handle_release_worktree_handles::handle_release_worktree_handles(
state, &cache_dir,
)
.await;
assert!(
matches!(resp, Response::Error { ref message } if message.contains("cache root")),
"expected refusal naming the cache root, got: {resp:?}"
);
assert!(
state.sessions.get(&sid).is_some(),
"refusal must not have torn down any sessions"
);
})
.await;
}
#[tokio::test]
#[ignore] async fn release_with_no_matches_returns_zero_counts() {
crate::test_support::test_timeout(async {
let cache_tmp = tempfile::tempdir().unwrap();
let _env = CacheDirEnvGuard::set(cache_tmp.path());
let endpoint = crate::ipc::unique_test_endpoint();
let cache_dir = NormalizedPath::new(cache_tmp.path());
let server = DaemonServer::bind_with_cache_dir(&endpoint, &cache_dir).unwrap();
let state = server.test_state();
let other_worktree = tempfile::tempdir().unwrap();
let sid = state
.sessions
.create(session_under(other_worktree.path(), None));
let target_tmp = tempfile::tempdir().unwrap();
let target = NormalizedPath::new(target_tmp.path());
let resp = super::super::handle_release_worktree_handles::handle_release_worktree_handles(
state, &target,
)
.await;
let Response::ReleaseWorktreeHandlesResult {
inspected,
released,
sessions_dropped,
unreleased,
} = resp
else {
panic!("expected ReleaseWorktreeHandlesResult, got: {resp:?}");
};
assert_eq!(inspected, 1);
assert_eq!(released, 0);
assert!(sessions_dropped.is_empty());
assert!(unreleased.is_empty());
assert!(state.sessions.get(&sid).is_some());
})
.await;
}