diff --git a/cloud-hypervisor/tests/common/tests_wrappers.rs b/cloud-hypervisor/tests/common/tests_wrappers.rs index a236db3d5..9d42a3f80 100644 --- a/cloud-hypervisor/tests/common/tests_wrappers.rs +++ b/cloud-hypervisor/tests/common/tests_wrappers.rs @@ -256,6 +256,11 @@ pub(crate) fn _test_pty_interaction(pty_path: PathBuf) { .open(pty_path) .unwrap(); + // Read concurrently so we drain the replayed backlog instead of leaving + // it stranded behind a non-reading client (which would back-pressure the + // sender and never let the login keystrokes through). + let ptyc = pty_read(cf.try_clone().unwrap()); + // Some dumb sleeps but we don't want to write // before the console is up and we don't want // to try and write the next line before the @@ -268,31 +273,28 @@ pub(crate) fn _test_pty_interaction(pty_path: PathBuf) { assert_eq!(cf.write(b"echo test_pty_console\n").unwrap(), 22); thread::sleep(std::time::Duration::new(2, 0)); - // read pty and ensure they have a login shell - // some fairly hacky workarounds to avoid looping - // forever in case the channel is blocked getting output - let ptyc = pty_read(cf); - let mut empty = 0; let mut prev = String::new(); - loop { + // The console can stream continuously (e.g. journald forwarded to it), so + // bound the wait: a missing marker must not loop until the harness timeout. + for _ in 0..20 { thread::sleep(std::time::Duration::new(2, 0)); - match ptyc.try_recv() { - Ok(line) => { - empty = 0; - prev = prev + &line; - if prev.contains("test_pty_console") { - break; + // Drain everything available this round so a large replayed backlog + // does not take one 2s tick per chunk to get through. + loop { + match ptyc.try_recv() { + Ok(line) => { + prev = prev + &line; + if prev.contains("test_pty_console") { + return; + } } - } - Err(mpsc::TryRecvError::Empty) => { - empty += 1; - assert!(empty <= 5, "No login on pty"); - } - _ => { - panic!("No login on pty") + Err(mpsc::TryRecvError::Empty) => break, + Err(_) => panic!("No login on pty"), } } } + // Bounded out without ever seeing the marker: the login never completed. + panic!("No login on pty"); } pub(crate) fn test_cpu_topology( diff --git a/cloud-hypervisor/tests/common/utils.rs b/cloud-hypervisor/tests/common/utils.rs index 6a0ce7449..97a86c2db 100644 --- a/cloud-hypervisor/tests/common/utils.rs +++ b/cloud-hypervisor/tests/common/utils.rs @@ -780,14 +780,13 @@ pub(super) fn pty_read(mut pty: std::fs::File) -> Receiver { let (tx, rx) = mpsc::channel::(); thread::spawn(move || { loop { - thread::sleep(std::time::Duration::new(1, 0)); - let mut buf = [0; 512]; + let mut buf = [0; 4096]; match pty.read(&mut buf) { - Ok(_bytes) => { - let output = std::str::from_utf8(&buf).unwrap().to_string(); - match tx.send(output) { - Ok(_) => (), - Err(_) => break, + Ok(0) => break, + Ok(bytes) => { + let output = String::from_utf8_lossy(&buf[..bytes]).into_owned(); + if tx.send(output).is_err() { + break; } } Err(_) => break, diff --git a/cloud-hypervisor/tests/integration.rs b/cloud-hypervisor/tests/integration.rs index 988a49969..19df8a6dd 100644 --- a/cloud-hypervisor/tests/integration.rs +++ b/cloud-hypervisor/tests/integration.rs @@ -2536,7 +2536,7 @@ mod common_parallel { let mut socat_command = Command::new("socat"); let socat_args = [ - &format!("pty,link={},raw", serial_socket_pty.display()), + &format!("pty,link={},raw,echo=0", serial_socket_pty.display()), &format!("UNIX-CONNECT:{}", serial_socket.display()), ]; socat_command.args(socat_args);