Serve concurrent terminal sessions with exact teardown
This commit is contained in:
parent
917409fcc6
commit
254bb37764
1 changed files with 278 additions and 51 deletions
|
|
@ -302,6 +302,23 @@ fn run_session_terminal_matrix() -> Result<(), MatrixError> {
|
|||
.store
|
||||
.apply(&[DomainStoreMutation::PutSession(session.clone())])
|
||||
.map_err(failure)?;
|
||||
let second_session_id = SessionId::new([41; 32]);
|
||||
let mut second_session = Session {
|
||||
generation_id: GenerationId::new(7),
|
||||
session_id: second_session_id,
|
||||
cli_id: ClientId::new([42; 32]),
|
||||
session_anchor_id: SessionAnchorId::new([43; 32]),
|
||||
session_phase: SessionPhase::Registering,
|
||||
};
|
||||
fixture
|
||||
.store
|
||||
.apply(&[DomainStoreMutation::PutSession(second_session.clone())])
|
||||
.map_err(failure)?;
|
||||
second_session.session_phase = SessionPhase::Attached;
|
||||
fixture
|
||||
.store
|
||||
.apply(&[DomainStoreMutation::PutSession(second_session)])
|
||||
.map_err(failure)?;
|
||||
session.session_phase = SessionPhase::Attached;
|
||||
fixture
|
||||
.store
|
||||
|
|
@ -317,6 +334,9 @@ fn run_session_terminal_matrix() -> Result<(), MatrixError> {
|
|||
let count = workspace.join("session-count");
|
||||
let finish = workspace.join("session-finish");
|
||||
let signals = workspace.join("session-signals");
|
||||
let second_count = workspace.join("session-second-count");
|
||||
let second_finish = workspace.join("session-second-finish");
|
||||
let second_signals = workspace.join("session-second-signals");
|
||||
let line = "x".repeat(1024);
|
||||
let script = format!(
|
||||
"trap 'echo INT >> /workspace/session-signals' INT; \
|
||||
|
|
@ -326,6 +346,15 @@ fn run_session_terminal_matrix() -> Result<(), MatrixError> {
|
|||
n=0; while test ! -e /workspace/session-finish; do \
|
||||
echo '{line}'; n=$((n+1)); echo $n > /workspace/session-count; done; exit 23"
|
||||
);
|
||||
let second_line = "y".repeat(1024);
|
||||
let second_script = format!(
|
||||
"trap 'echo INT >> /workspace/session-second-signals' INT; \
|
||||
trap 'echo QUIT >> /workspace/session-second-signals' QUIT; \
|
||||
trap 'echo TSTP >> /workspace/session-second-signals' TSTP; \
|
||||
trap 'echo WINCH >> /workspace/session-second-signals' WINCH; \
|
||||
n=0; while test ! -e /workspace/session-second-finish; do \
|
||||
echo '{second_line}'; n=$((n+1)); echo $n > /workspace/session-second-count; done; exit 42"
|
||||
);
|
||||
let request = TerminalAcquisition {
|
||||
domain_id: fixture.configuration.domain_id(),
|
||||
generation_id: GenerationId::new(7),
|
||||
|
|
@ -344,7 +373,20 @@ fn run_session_terminal_matrix() -> Result<(), MatrixError> {
|
|||
Arc::new(NoActivePrompt),
|
||||
);
|
||||
engine.acquire(&request).map_err(failure)?;
|
||||
engine
|
||||
.acquire(&TerminalAcquisition {
|
||||
session_id: second_session_id,
|
||||
internal_pid_file: runtime_domain.join("session-second-internal.pid"),
|
||||
argv: vec![
|
||||
b"/bin/sh".to_vec(),
|
||||
b"-c".to_vec(),
|
||||
second_script.into_bytes(),
|
||||
],
|
||||
..request.clone()
|
||||
})
|
||||
.map_err(failure)?;
|
||||
wait_for_path(&count)?;
|
||||
wait_for_path(&second_count)?;
|
||||
let running = fixture
|
||||
.store
|
||||
.snapshot()
|
||||
|
|
@ -384,6 +426,9 @@ fn run_session_terminal_matrix() -> Result<(), MatrixError> {
|
|||
.map_err(failure)?;
|
||||
}
|
||||
wait_for_signal_lines(&mut engine, session_id, &signals, 4)?;
|
||||
if second_signals.exists() {
|
||||
return Err(failure("terminal signals crossed Session IDs"));
|
||||
}
|
||||
let mut forwarded_before_prompt = 0_usize;
|
||||
for _ in 0..2_000 {
|
||||
let messages = engine
|
||||
|
|
@ -417,11 +462,21 @@ fn run_session_terminal_matrix() -> Result<(), MatrixError> {
|
|||
.map_err(failure)?;
|
||||
thread::sleep(Duration::from_millis(300));
|
||||
let before = fs::read_to_string(&count)?;
|
||||
thread::sleep(Duration::from_millis(300));
|
||||
let second_before = fs::read_to_string(&second_count)?;
|
||||
for _ in 0..60 {
|
||||
engine
|
||||
.poll(second_session_id, GenerationId::new(7))
|
||||
.map_err(failure)?;
|
||||
thread::sleep(Duration::from_millis(5));
|
||||
}
|
||||
let after = fs::read_to_string(&count)?;
|
||||
let second_after = fs::read_to_string(&second_count)?;
|
||||
if before != after {
|
||||
return Err(failure("prompt route did not apply PTY backpressure"));
|
||||
}
|
||||
if second_before == second_after {
|
||||
return Err(failure("one Prompt paused another Session Terminal"));
|
||||
}
|
||||
session.session_phase = SessionPhase::Attached;
|
||||
fixture
|
||||
.store
|
||||
|
|
@ -466,11 +521,49 @@ fn run_session_terminal_matrix() -> Result<(), MatrixError> {
|
|||
}
|
||||
if exit.and_then(lazaret_core::records::SessionExit::exit_code) != Some(23)
|
||||
|| engine.contains(session_id)
|
||||
|| !engine.contains(second_session_id)
|
||||
{
|
||||
return Err(failure(
|
||||
"Session Terminal exit or no-reattachment cleanup failed",
|
||||
));
|
||||
}
|
||||
let second_before_first_exit = fs::read_to_string(&second_count)?;
|
||||
for _ in 0..200 {
|
||||
engine
|
||||
.poll(second_session_id, GenerationId::new(7))
|
||||
.map_err(failure)?;
|
||||
if fs::read_to_string(&second_count).ok().as_deref()
|
||||
!= Some(second_before_first_exit.as_str())
|
||||
{
|
||||
break;
|
||||
}
|
||||
thread::sleep(Duration::from_millis(5));
|
||||
}
|
||||
if fs::read_to_string(&second_count).ok().as_deref() == Some(second_before_first_exit.as_str())
|
||||
{
|
||||
return Err(failure("first Session exit paused the second Session"));
|
||||
}
|
||||
fs::write(&second_finish, b"finish")?;
|
||||
let mut second_exit = None;
|
||||
for _ in 0..2_000 {
|
||||
for message in engine
|
||||
.poll(second_session_id, GenerationId::new(7))
|
||||
.map_err(failure)?
|
||||
{
|
||||
if let SessionTerminalMessage::Exit(outcome) = message {
|
||||
second_exit = Some(outcome);
|
||||
}
|
||||
}
|
||||
if second_exit.is_some() {
|
||||
break;
|
||||
}
|
||||
thread::sleep(Duration::from_millis(5));
|
||||
}
|
||||
if second_exit.and_then(lazaret_core::records::SessionExit::exit_code) != Some(42)
|
||||
|| engine.contains(second_session_id)
|
||||
{
|
||||
return Err(failure("second Session exit routing or cleanup failed"));
|
||||
}
|
||||
runtime
|
||||
.stop(&SandboxCoordinator::new(&fixture.store))
|
||||
.map_err(failure)
|
||||
|
|
|
|||
Loading…
Reference in a new issue