use std::path::PathBuf;
use tempfile::TempDir;
use super::manager::{ManagedTmuxDriver, SessionManager};
use super::record::ManagedSessionState;
use super::tests::FakeTmuxDriver;
#[tokio::test]
async fn manager_naming_convention() {
let dir = TempDir::new().unwrap();
let fake = FakeTmuxDriver::new();
let mgr = SessionManager::new(dir.path(), fake.clone()).await.unwrap();
let record = mgr
.create(
"task".into(),
Some(PathBuf::from("/tmp/wt1")),
None,
None,
None,
None,
)
.await
.expect("create");
assert!(record.tmux_name.starts_with("tm-"), "has tm- prefix");
let suffix = record
.tmux_name
.rsplit('-')
.next()
.expect("name has at least one dash-delimited segment");
assert_eq!(
suffix.len(),
2,
"serial suffix is exactly 2 digits: {}",
record.tmux_name
);
assert!(
suffix.bytes().all(|b| b.is_ascii_digit()),
"serial suffix is numeric: {}",
record.tmux_name
);
let serial: u8 = suffix.parse().expect("suffix is numeric (checked above)");
assert!(
(1..=99).contains(&serial),
"serial is in 01-99: {}",
record.tmux_name
);
}
#[tokio::test]
async fn manager_serial_reuses_decommissioned_gap() {
let dir = TempDir::new().unwrap();
let fake = FakeTmuxDriver::new();
let mgr = SessionManager::new(dir.path(), fake.clone()).await.unwrap();
let repo_url = Some("https://github.com/acme/gap-test".to_string());
let r1 = mgr
.create(
"t1".into(),
Some(PathBuf::from("/tmp/g1")),
None,
None,
repo_url.clone(),
None,
)
.await
.expect("create r1");
let r2 = mgr
.create(
"t2".into(),
Some(PathBuf::from("/tmp/g2")),
None,
None,
repo_url.clone(),
None,
)
.await
.expect("create r2");
let r3 = mgr
.create(
"t3".into(),
Some(PathBuf::from("/tmp/g3")),
None,
None,
repo_url.clone(),
None,
)
.await
.expect("create r3");
assert_eq!(r1.tmux_name, "tm-gap-test-01");
assert_eq!(r2.tmux_name, "tm-gap-test-02");
assert_eq!(r3.tmux_name, "tm-gap-test-03");
{
let mut store = mgr.store.write().await;
let mut rec = store.get(&r2.id).await.expect("get r2");
rec.state = ManagedSessionState::Decommissioned;
store.upsert(rec).await.expect("upsert decommissioned r2");
}
fake.kill_session(&r2.tmux_name).expect("kill r2 tmux");
let r4 = mgr
.create(
"t4".into(),
Some(PathBuf::from("/tmp/g4")),
None,
None,
repo_url.clone(),
None,
)
.await
.expect("create r4");
assert_eq!(
r4.tmux_name, "tm-gap-test-02",
"decommissioned serial 02 must be reused, got {}",
r4.tmux_name
);
}
#[tokio::test]
async fn manager_reconcile_adopts_new_prefix_session() {
let dir = TempDir::new().unwrap();
let fake = FakeTmuxDriver::new();
fake.seeded_names
.lock()
.unwrap()
.push("tm-trusty-tools-01".into());
let mgr = SessionManager::new(dir.path(), fake.clone()).await.unwrap();
let report = mgr.reconcile_on_boot(false).await.expect("reconcile");
assert!(
report
.external_adopted
.contains(&"tm-trusty-tools-01".to_string()),
"a live tm-prefixed session must be externally adopted; report: {report:?}"
);
let listed = mgr.list().await;
let adopted = listed
.iter()
.find(|r| r.tmux_name == "tm-trusty-tools-01")
.expect("adopted record present");
assert_eq!(adopted.state, ManagedSessionState::Active);
}