Isolate interactive terminal session ownership

This commit is contained in:
ms2k 2026-08-01 00:00:47 +09:00
commit 690738d846

View file

@ -321,15 +321,20 @@ fn changed_guest_identity_refuses_numeric_group_action() {
Err(TerminalError::GuestIdentityMismatch)
));
assert!(factory.log.lock().unwrap().is_empty());
assert!(matches!(
engine.handle(
let messages = engine
.handle(
GenerationId::new(7),
SessionTerminalEvent::Close(lazaret_core::records::SessionClose {
session_id: session,
}),
),
Err(TerminalError::GuestIdentityMismatch)
));
)
.unwrap();
assert!(
messages
.iter()
.any(|message| matches!(message, SessionTerminalMessage::Exit(_)))
);
assert!(!engine.contains(session));
assert_eq!(
fixture.store.snapshot().unwrap().session_terminals[0].state(),
SessionTerminalState::ReleaseIntent
@ -337,7 +342,7 @@ fn changed_guest_identity_refuses_numeric_group_action() {
}
#[test]
fn absent_leader_with_live_group_retains_release_until_group_is_empty() {
fn absent_leader_with_live_group_closes_with_release_intent() {
let session = id(6);
let (fixture, factory, mut engine) = setup(&[session]);
engine.acquire(&acquisition(session)).unwrap();
@ -347,25 +352,7 @@ fn absent_leader_with_live_group_retains_release_until_group_is_empty() {
state.guest.leader_present = false;
state.guest.group_present = true;
}
assert!(matches!(
engine.handle(
GenerationId::new(7),
SessionTerminalEvent::Close(lazaret_core::records::SessionClose {
session_id: session,
}),
),
Err(TerminalError::GuestIdentityMismatch)
));
let state = factory.state(0);
assert!(state.lock().unwrap().resources.exec_reaped);
assert!(!state.lock().unwrap().resources.pty_open);
assert_eq!(
fixture.store.snapshot().unwrap().session_terminals[0].state(),
SessionTerminalState::ReleaseIntent
);
state.lock().unwrap().guest.group_present = false;
engine
let messages = engine
.handle(
GenerationId::new(7),
SessionTerminalEvent::Close(lazaret_core::records::SessionClose {
@ -373,9 +360,73 @@ fn absent_leader_with_live_group_retains_release_until_group_is_empty() {
}),
)
.unwrap();
let state = factory.state(0);
assert!(state.lock().unwrap().resources.exec_reaped);
assert!(!state.lock().unwrap().resources.pty_open);
assert!(
messages
.iter()
.any(|message| matches!(message, SessionTerminalMessage::Exit(_)))
);
assert!(!engine.contains(session));
assert_eq!(
fixture.store.snapshot().unwrap().session_terminals[0].state(),
SessionTerminalState::Clean
SessionTerminalState::ReleaseIntent
);
}
#[test]
fn exited_exec_with_absent_leader_emits_exit_and_retains_group_release() {
let session = id(6);
let (fixture, factory, mut engine) = setup(&[session]);
engine.acquire(&acquisition(session)).unwrap();
{
let state = factory.state(0);
let mut state = state.lock().unwrap();
state.guest.leader_present = false;
state.guest.group_present = true;
state.resources.exec_exited = true;
}
let messages = engine.poll(session, GenerationId::new(7)).unwrap();
assert!(
messages
.iter()
.any(|message| matches!(message, SessionTerminalMessage::Exit(_)))
);
assert!(!engine.contains(session));
assert_eq!(
fixture.store.snapshot().unwrap().session_terminals[0].state(),
SessionTerminalState::ReleaseIntent
);
}
#[test]
fn persistent_guest_group_closes_session_with_release_intent() {
let session = id(6);
let (fixture, factory, mut engine) = setup(&[session]);
engine.acquire(&acquisition(session)).unwrap();
factory.state(0).lock().unwrap().guest.clears_after_signal = "never";
let messages = engine
.handle(
GenerationId::new(7),
SessionTerminalEvent::Close(lazaret_core::records::SessionClose {
session_id: session,
}),
)
.unwrap();
assert!(
messages
.iter()
.any(|message| matches!(message, SessionTerminalMessage::Exit(_)))
);
assert!(!engine.contains(session));
assert_eq!(
fixture.store.snapshot().unwrap().session_terminals[0].state(),
SessionTerminalState::ReleaseIntent
);
}