use super::decommission::WORKTREE_SENTINEL_FILE;
use super::manager::SessionManager;
use super::record::{ManagedSessionId, ManagedSessionState};
use super::tests::FakeTmuxDriver;
#[tokio::test]
async fn manager_decommission_removes_real_git_worktree() {
let dir = crate::test_support::hermetic_temp_dir();
let fake = FakeTmuxDriver::new();
let mgr = SessionManager::new(dir.path(), fake)
.await
.expect("manager");
let base_dir = crate::test_support::hermetic_temp_dir();
let base = base_dir.path().to_path_buf();
let git_init_ok = std::process::Command::new("git")
.arg("init")
.current_dir(&base)
.status()
.map(|s| s.success())
.unwrap_or(false);
if !git_init_ok {
eprintln!("manager_decommission_removes_real_git_worktree: git unavailable, skipping");
return;
}
let _ = std::process::Command::new("git")
.args([
"-C",
base.to_str().unwrap(),
"config",
"user.email",
"ci@test.invalid",
])
.status();
let _ = std::process::Command::new("git")
.args(["-C", base.to_str().unwrap(), "config", "user.name", "CI"])
.status();
let commit_ok = std::process::Command::new("git")
.args([
"-C",
base.to_str().unwrap(),
"commit",
"--allow-empty",
"-m",
"init",
])
.status()
.map(|s| s.success())
.unwrap_or(false);
if !commit_ok {
eprintln!("manager_decommission_removes_real_git_worktree: git commit failed, skipping");
return;
}
let session_name = "test-session-1806";
let branch_name = crate::core::worktree_naming::worktree_branch_for(session_name);
let worktrees_dir = base.join(".worktrees");
std::fs::create_dir_all(&worktrees_dir).unwrap();
let worktree_path = worktrees_dir.join(session_name);
let add_ok = std::process::Command::new("git")
.args([
"-C",
base.to_str().unwrap(),
"worktree",
"add",
"-b",
&branch_name,
])
.arg(&worktree_path)
.status()
.map(|s| s.success())
.unwrap_or(false);
assert!(add_ok, "git worktree add must succeed in this test fixture");
std::fs::write(worktree_path.join(WORKTREE_SENTINEL_FILE), b"").expect("write sentinel");
let record = mgr
.create_with_id(
ManagedSessionId::new(),
"task".into(),
Some(worktree_path.clone()),
None,
Some(worktree_path.clone()),
None,
None,
crate::runtime::RuntimeKind::default(),
false,
false, )
.await
.expect("create");
let managed_root = crate::test_support::hermetic_temp_dir();
let (tombstone, workspace_removed) = mgr
.decommission_with_root(&record.id, managed_root.path(), None)
.await
.expect("decommission");
assert!(
workspace_removed,
"workspace_removed must be true for an in-project git worktree (#1806)"
);
assert_eq!(tombstone.state, ManagedSessionState::Decommissioned);
assert!(
!worktree_path.exists(),
"the worktree directory must be removed from disk after decommission (#1806)"
);
let list_out = std::process::Command::new("git")
.args(["-C", base.to_str().unwrap(), "worktree", "list"])
.output()
.expect("git worktree list");
let list_stdout = String::from_utf8_lossy(&list_out.stdout);
assert!(
!list_stdout.contains(session_name),
"git worktree list must not reference the removed worktree; got: {list_stdout}"
);
let branch_out = std::process::Command::new("git")
.args([
"-C",
base.to_str().unwrap(),
"branch",
"--list",
&branch_name,
])
.output()
.expect("git branch --list");
let branch_stdout = String::from_utf8_lossy(&branch_out.stdout);
assert!(
branch_stdout.trim().is_empty(),
"the session branch ref must be deleted after decommission; got: {branch_stdout}"
);
}