test(cli): use real server for compliant peers
This commit is contained in:
4 files changed
+99
-59
No files matched your search
@@ -55,3 +55,7 @@ irtt-server = { workspace = true, optional = true }
|
|||||||
irtt-stats = { workspace = true, optional = true }
|
irtt-stats = { workspace = true, optional = true }
|
||||||
ratatui = { version = "0.30.2", optional = true }
|
ratatui = { version = "0.30.2", optional = true }
|
||||||
tokio = { version = "1.53.1", default-features = false, features = ["rt", "time"], optional = true }
|
tokio = { version = "1.53.1", default-features = false, features = ["rt", "time"], optional = true }
|
||||||
|
|
||||||
|
[dev-dependencies]
|
||||||
|
irtt-server.workspace = true
|
||||||
|
tokio = { version = "1.53.1", default-features = false, features = ["rt", "sync"] }
|
||||||
@@ -1,5 +1,8 @@
|
|||||||
#![cfg(feature = "client")]
|
#![cfg(feature = "client")]
|
||||||
|
|
||||||
|
#[path = "support/in_tree_server.rs"]
|
||||||
|
mod in_tree_server;
|
||||||
|
|
||||||
use std::{
|
use std::{
|
||||||
io::Read,
|
io::Read,
|
||||||
net::{SocketAddr, UdpSocket},
|
net::{SocketAddr, UdpSocket},
|
||||||
@@ -10,6 +13,7 @@ use std::{
|
|||||||
time::{Duration, Instant},
|
time::{Duration, Instant},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use in_tree_server::InTreeServer;
|
||||||
use irtt_proto::{
|
use irtt_proto::{
|
||||||
echo_packet_len, encode_echo_reply, encode_open_reply,
|
echo_packet_len, encode_echo_reply, encode_open_reply,
|
||||||
flags::{FLAG_CLOSE, FLAG_OPEN, FLAG_REPLY},
|
flags::{FLAG_CLOSE, FLAG_OPEN, FLAG_REPLY},
|
||||||
@@ -69,10 +73,7 @@ fn list_columns_succeeds_without_target() {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn single_target_default_table_omits_target_and_accepts_pacing() {
|
fn single_target_default_table_omits_target_and_accepts_pacing() {
|
||||||
let server = start_echo_server(test_params(
|
let server = InTreeServer::start();
|
||||||
Some(Duration::from_millis(30)),
|
|
||||||
Duration::from_millis(10),
|
|
||||||
));
|
|
||||||
|
|
||||||
let output = Command::new(env!("CARGO_BIN_EXE_irtt-cli"))
|
let output = Command::new(env!("CARGO_BIN_EXE_irtt-cli"))
|
||||||
.args([
|
.args([
|
||||||
@@ -89,7 +90,7 @@ fn single_target_default_table_omits_target_and_accepts_pacing() {
|
|||||||
.output()
|
.output()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
server.join();
|
drop(server);
|
||||||
|
|
||||||
assert!(
|
assert!(
|
||||||
output.status.success(),
|
output.status.success(),
|
||||||
@@ -104,10 +105,7 @@ fn single_target_default_table_omits_target_and_accepts_pacing() {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn single_target_custom_target_column_renders_positional_label() {
|
fn single_target_custom_target_column_renders_positional_label() {
|
||||||
let server = start_echo_server(test_params(
|
let server = InTreeServer::start();
|
||||||
Some(Duration::from_millis(30)),
|
|
||||||
Duration::from_millis(10),
|
|
||||||
));
|
|
||||||
let target = server.addr.to_string();
|
let target = server.addr.to_string();
|
||||||
|
|
||||||
let output = Command::new(env!("CARGO_BIN_EXE_irtt-cli"))
|
let output = Command::new(env!("CARGO_BIN_EXE_irtt-cli"))
|
||||||
@@ -127,7 +125,7 @@ fn single_target_custom_target_column_renders_positional_label() {
|
|||||||
.output()
|
.output()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
server.join();
|
drop(server);
|
||||||
|
|
||||||
assert!(
|
assert!(
|
||||||
output.status.success(),
|
output.status.success(),
|
||||||
@@ -238,9 +236,8 @@ fn continuous_single_target_interruption_drains_final_events_and_succeeds() {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn multi_target_csv_emits_rows_for_both_labels() {
|
fn multi_target_csv_emits_rows_for_both_labels() {
|
||||||
let params = test_params(Some(Duration::from_millis(40)), Duration::from_millis(10));
|
let a = InTreeServer::start();
|
||||||
let a = start_echo_server(params.clone());
|
let b = InTreeServer::start();
|
||||||
let b = start_echo_server(params);
|
|
||||||
|
|
||||||
let output = Command::new(env!("CARGO_BIN_EXE_irtt-cli"))
|
let output = Command::new(env!("CARGO_BIN_EXE_irtt-cli"))
|
||||||
.args([
|
.args([
|
||||||
@@ -262,8 +259,8 @@ fn multi_target_csv_emits_rows_for_both_labels() {
|
|||||||
.output()
|
.output()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
a.join();
|
drop(a);
|
||||||
b.join();
|
drop(b);
|
||||||
|
|
||||||
assert!(
|
assert!(
|
||||||
output.status.success(),
|
output.status.success(),
|
||||||
@@ -643,20 +640,9 @@ fn wait_with_timeout(mut child: std::process::Child, timeout: Duration) -> Outpu
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn start_echo_server(params: Params) -> FakeServer {
|
|
||||||
start_echo_server_inner(params, None)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn start_echo_server_with_first_reply(
|
fn start_echo_server_with_first_reply(
|
||||||
params: Params,
|
params: Params,
|
||||||
first_reply_tx: mpsc::Sender<()>,
|
first_reply_tx: mpsc::Sender<()>,
|
||||||
) -> FakeServer {
|
|
||||||
start_echo_server_inner(params, Some(first_reply_tx))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn start_echo_server_inner(
|
|
||||||
params: Params,
|
|
||||||
mut first_reply_tx: Option<mpsc::Sender<()>>,
|
|
||||||
) -> FakeServer {
|
) -> FakeServer {
|
||||||
let socket = UdpSocket::bind("127.0.0.1:0").unwrap();
|
let socket = UdpSocket::bind("127.0.0.1:0").unwrap();
|
||||||
socket
|
socket
|
||||||
@@ -664,6 +650,7 @@ fn start_echo_server_inner(
|
|||||||
.unwrap();
|
.unwrap();
|
||||||
let addr = socket.local_addr().unwrap();
|
let addr = socket.local_addr().unwrap();
|
||||||
let done = thread::spawn(move || {
|
let done = thread::spawn(move || {
|
||||||
|
let mut first_reply_tx = Some(first_reply_tx);
|
||||||
let (_, peer) = recv_request(&socket);
|
let (_, peer) = recv_request(&socket);
|
||||||
socket
|
socket
|
||||||
.send_to(&open_reply(FLAG_OPEN | FLAG_REPLY, TOKEN, ¶ms), peer)
|
.send_to(&open_reply(FLAG_OPEN | FLAG_REPLY, TOKEN, ¶ms), peer)
|
||||||
|
|||||||
@@ -0,0 +1,74 @@
|
|||||||
|
use std::{
|
||||||
|
net::{IpAddr, Ipv4Addr, SocketAddr},
|
||||||
|
sync::mpsc,
|
||||||
|
thread::{self, JoinHandle},
|
||||||
|
time::Duration,
|
||||||
|
};
|
||||||
|
|
||||||
|
use irtt_server::{Server, ServerConfig};
|
||||||
|
use tokio::sync::oneshot;
|
||||||
|
|
||||||
|
const STARTUP_TIMEOUT: Duration = Duration::from_secs(2);
|
||||||
|
|
||||||
|
pub struct InTreeServer {
|
||||||
|
pub addr: SocketAddr,
|
||||||
|
shutdown: Option<oneshot::Sender<()>>,
|
||||||
|
done: Option<JoinHandle<Result<(), irtt_server::ServerRuntimeError>>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl InTreeServer {
|
||||||
|
pub fn start() -> Self {
|
||||||
|
let (startup_tx, startup_rx) = mpsc::sync_channel(1);
|
||||||
|
let (shutdown_tx, shutdown_rx) = oneshot::channel();
|
||||||
|
let done = thread::spawn(move || {
|
||||||
|
let runtime = tokio::runtime::Builder::new_current_thread()
|
||||||
|
.enable_all()
|
||||||
|
.build()
|
||||||
|
.expect("failed to build in-tree test server runtime");
|
||||||
|
runtime.block_on(async move {
|
||||||
|
let bind_addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::LOCALHOST), 0);
|
||||||
|
let mut server = Server::bind(bind_addr, ServerConfig::default()).await?;
|
||||||
|
startup_tx
|
||||||
|
.send(server.local_addr()?)
|
||||||
|
.expect("test stopped waiting for in-tree server startup");
|
||||||
|
server
|
||||||
|
.run(async {
|
||||||
|
let _ = shutdown_rx.await;
|
||||||
|
})
|
||||||
|
.await
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
let addr = match startup_rx.recv_timeout(STARTUP_TIMEOUT) {
|
||||||
|
Ok(addr) => addr,
|
||||||
|
Err(error) => {
|
||||||
|
let _ = shutdown_tx.send(());
|
||||||
|
let result = done.join().expect("in-tree test server thread panicked");
|
||||||
|
panic!("in-tree test server failed before startup ({error}): {result:?}");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Self {
|
||||||
|
addr,
|
||||||
|
shutdown: Some(shutdown_tx),
|
||||||
|
done: Some(done),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn stop(&mut self) {
|
||||||
|
if let Some(shutdown) = self.shutdown.take() {
|
||||||
|
let _ = shutdown.send(());
|
||||||
|
}
|
||||||
|
if let Some(done) = self.done.take() {
|
||||||
|
done.join()
|
||||||
|
.expect("in-tree test server thread panicked")
|
||||||
|
.expect("in-tree test server stopped with an error");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Drop for InTreeServer {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
self.stop();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -13,7 +13,7 @@ const STARTUP_TIMEOUT: Duration = Duration::from_secs(2);
|
|||||||
pub struct InTreeServer {
|
pub struct InTreeServer {
|
||||||
pub addr: SocketAddr,
|
pub addr: SocketAddr,
|
||||||
shutdown: Option<oneshot::Sender<()>>,
|
shutdown: Option<oneshot::Sender<()>>,
|
||||||
done: Option<JoinHandle<Result<(), String>>>,
|
done: Option<JoinHandle<Result<(), irtt_server::ServerRuntimeError>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl InTreeServer {
|
impl InTreeServer {
|
||||||
@@ -24,52 +24,27 @@ impl InTreeServer {
|
|||||||
let runtime = tokio::runtime::Builder::new_current_thread()
|
let runtime = tokio::runtime::Builder::new_current_thread()
|
||||||
.enable_all()
|
.enable_all()
|
||||||
.build()
|
.build()
|
||||||
.map_err(|error| format!("failed to build test server runtime: {error}"))?;
|
.expect("failed to build in-tree test server runtime");
|
||||||
runtime.block_on(async move {
|
runtime.block_on(async move {
|
||||||
let bind_addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::LOCALHOST), 0);
|
let bind_addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::LOCALHOST), 0);
|
||||||
let mut server = match Server::bind(bind_addr, config).await {
|
let mut server = Server::bind(bind_addr, config).await?;
|
||||||
Ok(server) => server,
|
|
||||||
Err(error) => {
|
|
||||||
let message = format!("failed to bind in-tree test server: {error}");
|
|
||||||
let _ = startup_tx.send(Err(message.clone()));
|
|
||||||
return Err(message);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
let addr = match server.local_addr() {
|
|
||||||
Ok(addr) => addr,
|
|
||||||
Err(error) => {
|
|
||||||
let message =
|
|
||||||
format!("failed to read in-tree test server address: {error}");
|
|
||||||
let _ = startup_tx.send(Err(message.clone()));
|
|
||||||
return Err(message);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
startup_tx
|
startup_tx
|
||||||
.send(Ok(addr))
|
.send(server.local_addr()?)
|
||||||
.map_err(|_| "test stopped waiting for in-tree server startup".to_owned())?;
|
.expect("test stopped waiting for in-tree server startup");
|
||||||
server
|
server
|
||||||
.run(async {
|
.run(async {
|
||||||
let _ = shutdown_rx.await;
|
let _ = shutdown_rx.await;
|
||||||
})
|
})
|
||||||
.await
|
.await
|
||||||
.map_err(|error| format!("in-tree test server failed: {error}"))
|
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
let addr = match startup_rx.recv_timeout(STARTUP_TIMEOUT) {
|
let addr = match startup_rx.recv_timeout(STARTUP_TIMEOUT) {
|
||||||
Ok(Ok(addr)) => addr,
|
Ok(addr) => addr,
|
||||||
Ok(Err(error)) => {
|
|
||||||
done.join()
|
|
||||||
.expect("in-tree test server thread panicked")
|
|
||||||
.ok();
|
|
||||||
panic!("{error}");
|
|
||||||
}
|
|
||||||
Err(error) => {
|
Err(error) => {
|
||||||
let _ = shutdown_tx.send(());
|
let _ = shutdown_tx.send(());
|
||||||
done.join()
|
let result = done.join().expect("in-tree test server thread panicked");
|
||||||
.expect("in-tree test server thread panicked")
|
panic!("in-tree test server failed before startup ({error}): {result:?}");
|
||||||
.ok();
|
|
||||||
panic!("timed out waiting for in-tree test server startup: {error}");
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
Reference in new issue
Block a user