use tempfile::TempDir;
use super::manager::{ManagedError, ManagedTmuxDriver};
use super::record::{ManagedSessionId, ManagedSessionState};
use super::tests::{make_manager, seed_record};
#[tokio::test]
async fn delete_record_stale_active_deletable_when_tmux_dead() {
let dir = TempDir::new().unwrap();
let (mgr, fake) = make_manager(&dir).await;
let id = ManagedSessionId::new();
seed_record(&mgr, &dir, id, ManagedSessionState::Active, false).await;
fake.kill_session(&format!("tmpm-seed-{id}"))
.expect("simulate tmux death");
mgr.delete_record(&id, false).await.expect(
"a stale Active record whose tmux is actually dead must be deletable without --force",
);
assert_eq!(
mgr.get(&id).await.expect("record still tracked").state,
ManagedSessionState::Deleted
);
}
#[tokio::test]
async fn prune_stale_active_removable_without_force_when_tmux_dead() {
let dir = TempDir::new().unwrap();
let (mgr, fake) = make_manager(&dir).await;
let stale = ManagedSessionId::new();
let live = ManagedSessionId::new();
seed_record(&mgr, &dir, stale, ManagedSessionState::Active, false).await;
seed_record(&mgr, &dir, live, ManagedSessionState::Active, false).await;
fake.kill_session(&format!("tmpm-seed-{stale}"))
.expect("simulate tmux death");
let outcome = mgr
.prune_managed(crate::session_manager::PruneFilter::All, false, false, None)
.await
.expect("prune all");
assert_eq!(
outcome.count(),
1,
"only the stale (tmux-dead) Active record is reaped"
);
assert_eq!(
mgr.get(&stale).await.unwrap().state,
ManagedSessionState::Decommissioned,
"stale Active with dead tmux must be reaped without --force (#2022)"
);
assert_eq!(
mgr.get(&live).await.unwrap().state,
ManagedSessionState::Active,
"a genuinely live (tmux-alive) session must still be guarded"
);
}
#[tokio::test]
async fn delete_record_refuses_when_the_tmux_probe_fails() {
let dir = TempDir::new().unwrap();
let (mgr, fake) = make_manager(&dir).await;
let id = ManagedSessionId::new();
seed_record(&mgr, &dir, id, ManagedSessionState::Active, false).await;
*fake.list_sessions_should_fail.lock().unwrap() = true;
let err = mgr
.delete_record(&id, false)
.await
.expect_err("an unobservable liveness probe must refuse the delete (#5859)");
assert!(
matches!(err, ManagedError::TmuxUnavailable(_)),
"expected TmuxUnavailable, got {err:?}"
);
assert_eq!(
mgr.get(&id).await.expect("record still tracked").state,
ManagedSessionState::Active,
"no record may be touched when liveness could not be established"
);
}
#[tokio::test]
async fn prune_refuses_when_the_tmux_probe_fails() {
let dir = TempDir::new().unwrap();
let (mgr, fake) = make_manager(&dir).await;
let id = ManagedSessionId::new();
seed_record(&mgr, &dir, id, ManagedSessionState::Active, false).await;
*fake.list_sessions_should_fail.lock().unwrap() = true;
let err = mgr
.prune_managed(crate::session_manager::PruneFilter::All, false, false, None)
.await
.expect_err("an unobservable liveness probe must refuse the prune (#5859)");
assert!(
matches!(err, ManagedError::TmuxUnavailable(_)),
"expected TmuxUnavailable, got {err:?}"
);
assert_eq!(
mgr.get(&id).await.expect("record still tracked").state,
ManagedSessionState::Active,
"a live session must survive a prune whose liveness probe failed"
);
let outcome = mgr
.prune_managed(crate::session_manager::PruneFilter::All, false, true, None)
.await
.expect("include_active skips the liveness gate entirely");
assert_eq!(outcome.count(), 1);
}
#[tokio::test]
async fn resume_refuses_when_the_tmux_probe_fails() {
let dir = TempDir::new().unwrap();
let (mgr, fake) = make_manager(&dir).await;
let id = ManagedSessionId::new();
seed_record(&mgr, &dir, id, ManagedSessionState::Stopped, false).await;
fake.seeded_names
.lock()
.unwrap()
.push(format!("tmpm-seed-{id}"));
*fake.list_sessions_should_fail.lock().unwrap() = true;
let err = mgr
.resume(&id)
.await
.expect_err("an unobservable liveness probe must refuse the resume (#5859)");
assert!(
matches!(err, ManagedError::TmuxUnavailable(_)),
"expected TmuxUnavailable, got {err:?}"
);
assert!(
fake.kill_calls.lock().unwrap().is_empty(),
"resume must not kill a pane it could not prove dead"
);
assert!(
fake.create_cwd_calls.lock().unwrap().is_empty(),
"resume must not rebuild a pane it could not prove dead"
);
assert_eq!(
mgr.get(&id).await.expect("record still tracked").state,
ManagedSessionState::Stopped
);
}
#[test]
fn session_exists_reads_an_unobservable_probe_as_absent() {
let fake = super::tests::FakeTmuxDriver::new();
*fake.list_sessions_should_fail.lock().unwrap() = true;
assert!(!fake.session_exists("tmpm-anything"));
assert!(matches!(
fake.session_exists_checked("tmpm-anything"),
Err(ManagedError::TmuxUnavailable(_))
));
}