test: address review gaps in timing and dynamic targets
This commit is contained in:
4 files changed
+211
-33
No files matched your search
@@ -256,3 +256,108 @@ fn server_command_line_binds_replace_the_environment_bind() {
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Exercise stdin replacement and EOF through the actual application process.
|
||||
#[cfg(feature = "client")]
|
||||
#[test]
|
||||
fn targets_stdin_supersedes_the_active_set_and_stops_on_eof() {
|
||||
use std::{
|
||||
io::{BufRead, BufReader, Read, Write},
|
||||
process::{Child, Stdio},
|
||||
sync::mpsc,
|
||||
thread,
|
||||
time::{Duration, Instant},
|
||||
};
|
||||
struct ClientProcess(Child);
|
||||
impl Drop for ClientProcess {
|
||||
fn drop(&mut self) {
|
||||
let _ = self.0.kill();
|
||||
let _ = self.0.wait();
|
||||
}
|
||||
}
|
||||
let server = in_tree_server::InTreeServer::start(ServerConfig::default());
|
||||
let mut client = ClientProcess(
|
||||
Command::new(env!("CARGO_BIN_EXE_irtt-client"))
|
||||
.env_clear()
|
||||
.args([
|
||||
"--duration",
|
||||
"0",
|
||||
"--targets-stdin",
|
||||
"--interval",
|
||||
"20ms",
|
||||
"--format",
|
||||
"jsonl",
|
||||
"--columns",
|
||||
"target,event",
|
||||
])
|
||||
.stdin(Stdio::piped())
|
||||
.stdout(Stdio::piped())
|
||||
.stderr(Stdio::piped())
|
||||
.spawn()
|
||||
.unwrap(),
|
||||
);
|
||||
let stdout = client.0.stdout.take().unwrap();
|
||||
let (tx, rx) = mpsc::channel();
|
||||
let reader = thread::spawn(move || {
|
||||
for line in BufReader::new(stdout).lines() {
|
||||
if tx.send(line.unwrap()).is_err() {
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
let mut stdin = client.0.stdin.take().unwrap();
|
||||
let mut rows = Vec::new();
|
||||
for target in ["first", "second"] {
|
||||
writeln!(stdin, "{target}={}", server.addr).unwrap();
|
||||
stdin.flush().unwrap();
|
||||
let deadline = Instant::now() + Duration::from_secs(5);
|
||||
loop {
|
||||
let row = rx
|
||||
.recv_timeout(deadline.saturating_duration_since(Instant::now()))
|
||||
.expect("stdin target set did not produce a reply");
|
||||
let replied = row.contains(&format!("\"target\":\"{target}\""))
|
||||
&& row.contains("\"event\":\"echo_reply\"");
|
||||
rows.push(row);
|
||||
if replied {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Retirement can finish after the newer target's first reply.
|
||||
let deadline = Instant::now() + Duration::from_secs(5);
|
||||
while !rows.iter().any(|row| {
|
||||
row.contains("\"target\":\"first\"") && row.contains("\"event\":\"session_closed\"")
|
||||
}) {
|
||||
rows.push(
|
||||
rx.recv_timeout(deadline.saturating_duration_since(Instant::now()))
|
||||
.expect("superseded stdin target did not retire"),
|
||||
);
|
||||
}
|
||||
drop(stdin);
|
||||
let deadline = Instant::now() + Duration::from_secs(5);
|
||||
let status = loop {
|
||||
if let Some(status) = client.0.try_wait().unwrap() {
|
||||
break status;
|
||||
}
|
||||
assert!(
|
||||
Instant::now() < deadline,
|
||||
"client did not terminate on stdin EOF"
|
||||
);
|
||||
thread::sleep(Duration::from_millis(10));
|
||||
};
|
||||
reader.join().unwrap();
|
||||
rows.extend(rx.try_iter());
|
||||
let mut stderr = String::new();
|
||||
client
|
||||
.0
|
||||
.stderr
|
||||
.take()
|
||||
.unwrap()
|
||||
.read_to_string(&mut stderr)
|
||||
.unwrap();
|
||||
assert!(status.success(), "{stderr}");
|
||||
assert!(rows
|
||||
.iter()
|
||||
.any(|row| row.contains("\"target\":\"second\"")
|
||||
&& row.contains("\"event\":\"session_closed\"")));
|
||||
}
|
||||
Reference in new issue
Block a user