-
Notifications
You must be signed in to change notification settings - Fork 1.3k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
move wasmtime-wasi's unit test for stdin to a separate integration te…
…st (#7564) * move wasmtime-wasi's unit test for stdin to a separate integration test fork is always a terrible idea, but when we wrote this test, we couldn't think of an alternative method. alex showed us how `/tests/host_segfault.rs` works, which solves a similar problem for measuring process behavior without forking. the forking version of this test would occasionally hang in the child's creation of a tokio runtime because std Once is not fork-safe (nor should it be. nothing should be fork-safe. forks are an abomination). so instead, this is now a separate integration test with `harness = false` that will exec itself in order to run the child. * wasmtime-wasi: add tests to package include
- Loading branch information
Pat Hickey
authored
Nov 21, 2023
1 parent
f7d16d8
commit 2e8e09a
Showing
3 changed files
with
171 additions
and
192 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,165 @@ | ||
use std::io::{BufRead, Write}; | ||
use std::process::Command; | ||
use wasmtime_wasi::preview2::{HostInputStream, Subscribe}; | ||
|
||
const VAR_NAME: &str = "__CHILD_PROCESS"; | ||
|
||
fn main() { | ||
if cfg!(miri) { | ||
return; | ||
} | ||
// Skip this tests if it looks like we're in a cross-compiled situation and | ||
// we're emulating this test for a different platform. In that scenario | ||
// emulators (like QEMU) tend to not report signals the same way and such. | ||
if std::env::vars() | ||
.filter(|(k, _v)| k.starts_with("CARGO_TARGET") && k.ends_with("RUNNER")) | ||
.count() | ||
> 0 | ||
{ | ||
return; | ||
} | ||
|
||
match std::env::var(VAR_NAME) { | ||
Ok(_) => child_process(), | ||
Err(_) => parent_process(), | ||
} | ||
|
||
fn child_process() { | ||
let mut result_write = std::io::stderr(); | ||
let mut child_running = true; | ||
while child_running { | ||
tokio::runtime::Builder::new_multi_thread() | ||
.enable_all() | ||
.build() | ||
.unwrap() | ||
.block_on(async { | ||
'task: loop { | ||
println!("child: creating stdin"); | ||
let mut stdin = wasmtime_wasi::preview2::stdin(); | ||
|
||
println!("child: checking that stdin is not ready"); | ||
assert!( | ||
tokio::time::timeout( | ||
std::time::Duration::from_millis(100), | ||
stdin.ready() | ||
) | ||
.await | ||
.is_err(), | ||
"stdin available too soon" | ||
); | ||
|
||
writeln!(&mut result_write, "start").unwrap(); | ||
|
||
println!("child: started"); | ||
|
||
let mut buffer = String::new(); | ||
loop { | ||
println!("child: waiting for stdin to be ready"); | ||
stdin.ready().await; | ||
|
||
println!("child: reading input"); | ||
// We can't effectively test for the case where stdin was closed, so panic if it is... | ||
let bytes = stdin.read(1024).unwrap(); | ||
|
||
println!("child got: {:?}", bytes); | ||
|
||
buffer.push_str(std::str::from_utf8(bytes.as_ref()).unwrap()); | ||
if let Some((line, rest)) = buffer.split_once('\n') { | ||
if line == "all done" { | ||
writeln!(&mut result_write, "done").unwrap(); | ||
println!("child: exiting..."); | ||
child_running = false; | ||
break 'task; | ||
} else if line == "restart_runtime" { | ||
writeln!(&mut result_write, "restarting").unwrap(); | ||
println!("child: restarting runtime..."); | ||
break 'task; | ||
} else if line == "restart_task" { | ||
writeln!(&mut result_write, "restarting").unwrap(); | ||
println!("child: restarting task..."); | ||
continue 'task; | ||
} else { | ||
writeln!(&mut result_write, "{}", line).unwrap(); | ||
} | ||
|
||
buffer = rest.to_owned(); | ||
} | ||
} | ||
} | ||
}); | ||
println!("child: runtime exited"); | ||
} | ||
println!("child: exiting"); | ||
} | ||
} | ||
|
||
fn parent_process() { | ||
let me = std::env::current_exe().unwrap(); | ||
let mut cmd = Command::new(me); | ||
cmd.env(VAR_NAME, "1"); | ||
cmd.stdin(std::process::Stdio::piped()); | ||
|
||
if std::env::args().any(|arg| arg == "--nocapture") { | ||
cmd.stdout(std::process::Stdio::inherit()); | ||
} else { | ||
cmd.stdout(std::process::Stdio::null()); | ||
} | ||
|
||
cmd.stderr(std::process::Stdio::piped()); | ||
let mut child = cmd.spawn().unwrap(); | ||
|
||
let mut stdin_write = child.stdin.take().unwrap(); | ||
let mut result_read = std::io::BufReader::new(child.stderr.take().unwrap()); | ||
|
||
let mut line = String::new(); | ||
result_read.read_line(&mut line).unwrap(); | ||
assert_eq!(line, "start\n"); | ||
|
||
for i in 0..5 { | ||
let message = format!("some bytes {}\n", i); | ||
stdin_write.write_all(message.as_bytes()).unwrap(); | ||
line.clear(); | ||
result_read.read_line(&mut line).unwrap(); | ||
assert_eq!(line, message); | ||
} | ||
|
||
writeln!(&mut stdin_write, "restart_task").unwrap(); | ||
line.clear(); | ||
result_read.read_line(&mut line).unwrap(); | ||
assert_eq!(line, "restarting\n"); | ||
line.clear(); | ||
|
||
result_read.read_line(&mut line).unwrap(); | ||
assert_eq!(line, "start\n"); | ||
|
||
for i in 0..10 { | ||
let message = format!("more bytes {}\n", i); | ||
stdin_write.write_all(message.as_bytes()).unwrap(); | ||
line.clear(); | ||
result_read.read_line(&mut line).unwrap(); | ||
assert_eq!(line, message); | ||
} | ||
|
||
writeln!(&mut stdin_write, "restart_runtime").unwrap(); | ||
line.clear(); | ||
result_read.read_line(&mut line).unwrap(); | ||
assert_eq!(line, "restarting\n"); | ||
line.clear(); | ||
|
||
result_read.read_line(&mut line).unwrap(); | ||
assert_eq!(line, "start\n"); | ||
|
||
for i in 0..17 { | ||
let message = format!("even more bytes {}\n", i); | ||
stdin_write.write_all(message.as_bytes()).unwrap(); | ||
line.clear(); | ||
result_read.read_line(&mut line).unwrap(); | ||
assert_eq!(line, message); | ||
} | ||
|
||
writeln!(&mut stdin_write, "all done").unwrap(); | ||
|
||
line.clear(); | ||
result_read.read_line(&mut line).unwrap(); | ||
assert_eq!(line, "done\n"); | ||
} |