Run non-interactive sessions through production coordination

This commit is contained in:
ms2k 2026-07-16 16:28:18 +09:00
commit 71b0266cf2

View file

@ -12,7 +12,9 @@ use lazaret_host_coordinator::lifecycle::{
DomainPhase, HostCoordinatorLifecycle, LifecycleAction, LifecycleAdapter, LifecycleError,
SessionAdmissionIdentity, SessionLifecycleAdapter,
};
use lazaret_host_coordinator::production::BootstrapOwnerGuard;
use lazaret_linux::filesystem::try_exclusive_flock;
use rustix::pipe::{PipeFlags, pipe_with};
#[derive(Clone, Default)]
struct RecordingAdapter {
@ -256,6 +258,61 @@ fn bootstrap_owner_guard_failure_uses_exact_modeled_disconnect_transition() {
);
}
#[test]
fn published_bootstrap_owner_eof_disconnects_waiting_session_and_tears_down() {
let directory = tempfile::tempdir().unwrap();
let store = open_store(&directory);
let (domain_adapter, session_adapter) = adapters();
let mut lifecycle = HostCoordinatorLifecycle::new(&store, domain_adapter, session_adapter);
let owner = session(10, 1);
lifecycle
.start_new_domain(generation(1), owner.clone())
.unwrap();
complete_startup(&mut lifecycle);
let (reader, writer) = pipe_with(PipeFlags::CLOEXEC).unwrap();
let owner_guard = BootstrapOwnerGuard::from_inherited(reader).unwrap();
drop(writer);
lifecycle
.reconcile_published_bootstrap_owner(owner.session_id, owner_guard.is_live().unwrap())
.unwrap();
assert_eq!(lifecycle.phase(), DomainPhase::Absent);
assert!(!lifecycle.is_published());
assert_eq!(
lifecycle.session_phase(owner.session_id),
Some(SessionPhase::Closed)
);
}
#[test]
fn admitted_bootstrap_owner_ignores_later_bootstrap_pipe_eof() {
let directory = tempfile::tempdir().unwrap();
let store = open_store(&directory);
let (domain_adapter, session_adapter) = adapters();
let mut lifecycle = HostCoordinatorLifecycle::new(&store, domain_adapter, session_adapter);
let owner = session(10, 1);
lifecycle
.start_new_domain(generation(1), owner.clone())
.unwrap();
complete_startup(&mut lifecycle);
lifecycle.admit_session(admission(owner.clone())).unwrap();
let (reader, writer) = pipe_with(PipeFlags::CLOEXEC).unwrap();
let owner_guard = BootstrapOwnerGuard::from_inherited(reader).unwrap();
drop(writer);
lifecycle
.reconcile_published_bootstrap_owner(owner.session_id, owner_guard.is_live().unwrap())
.unwrap();
assert_eq!(lifecycle.phase(), DomainPhase::Ready);
assert!(lifecycle.is_published());
assert_eq!(
lifecycle.session_phase(owner.session_id),
Some(SessionPhase::Attached)
);
}
#[test]
fn exact_start_join_disconnect_and_teardown_actions_are_ordered() {
let directory = tempfile::tempdir().unwrap();
@ -274,15 +331,10 @@ fn exact_start_join_disconnect_and_teardown_actions_are_ordered() {
lifecycle.admit_session(admission(waiter.clone())).unwrap();
lifecycle.disconnect_session(owner.session_id).unwrap();
assert!(!lifecycle.is_teardown_ready());
assert!(!lifecycle.teardown_if_idle().unwrap());
lifecycle.disconnect_session(waiter.session_id).unwrap();
assert!(lifecycle.is_teardown_ready());
lifecycle.begin_teardown().unwrap();
lifecycle.stop_sandbox().unwrap();
lifecycle.stop_sidecar().unwrap();
lifecycle.unmount_state_anchor().unwrap();
lifecycle.release_prepared_lower_lease().unwrap();
lifecycle.graceful_supervisor_exit().unwrap();
lifecycle.finish_teardown().unwrap();
assert!(lifecycle.teardown_if_idle().unwrap());
assert_eq!(lifecycle.phase(), DomainPhase::Absent);
assert!(!lifecycle.is_published());