test(client): use real server for compliant peers

This commit is contained in:
Nils Andreas Svee committed 2026-08-14 17:17:41 +07:00
1 parent cbef62be7a
commit fca7a2fcc6
9 files changed
+172 -50

No files matched your search

+1 -1
View File
@@ -276,7 +276,7 @@ fn assert_no_duplicate_late_or_warning(events: &[ClientEvent]) {
fn backend_hmac_correct_key_succeeds() {
let key = b"compat-secret".to_vec();
let params = default_params();
let peer = BackendPeer::start_open_echo(params.clone(), Some(key.clone()));
let peer = BackendPeer::start_open_echo(Some(key.clone()));
let mut config = config_for_params(peer.addr(), &params);
config.hmac_key = Some(key);
+1 -1
View File
@@ -83,7 +83,7 @@ fn echo_reply_bytes_consistent_with_echo_packet_len_for_various_lengths() {
#[test]
fn backend_large_packet_smoke() {
let params = params_with_length(1472);
let peer = BackendPeer::start_open_echo(params.clone(), None);
let peer = BackendPeer::start_open_echo(None);
let mut client = Client::connect(ClientConfig {
negotiation_policy: NegotiationPolicy::Loose,
length: 1472,
@@ -6,7 +6,7 @@ use crate::support::{config_for_params, default_params, params_for_modes, Backen
#[test]
fn backend_basic_open_echo_close() {
let params = default_params();
let peer = BackendPeer::start_open_echo(params.clone(), None);
let peer = BackendPeer::start_open_echo(None);
let mut client = Client::connect(config_for_params(peer.addr(), &params)).unwrap();
let outcome = client.open().unwrap();
@@ -31,7 +31,7 @@ fn backend_received_stats_smoke() {
ReceivedStats::Both,
] {
let params = params_for_modes(mode, StampAt::None, Clock::Both);
let peer = BackendPeer::start_open_echo(params.clone(), None);
let peer = BackendPeer::start_open_echo(None);
let mut client = Client::connect(config_for_params(peer.addr(), &params)).unwrap();
client.open().unwrap();
@@ -54,7 +54,7 @@ fn backend_timestamp_smoke() {
StampAt::Midpoint,
] {
let params = params_for_modes(ReceivedStats::None, mode, Clock::Both);
let peer = BackendPeer::start_open_echo(params.clone(), None);
let peer = BackendPeer::start_open_echo(None);
let mut client = Client::connect(config_for_params(peer.addr(), &params)).unwrap();
client.open().unwrap();
@@ -101,7 +101,7 @@ fn backend_timestamp_smoke() {
fn backend_clock_smoke() {
for clock in [Clock::Wall, Clock::Monotonic, Clock::Both] {
let params = params_for_modes(ReceivedStats::None, StampAt::Both, clock);
let peer = BackendPeer::start_open_echo(params.clone(), None);
let peer = BackendPeer::start_open_echo(None);
let mut client = Client::connect(config_for_params(peer.addr(), &params)).unwrap();
client.open().unwrap();
+16 -3
View File
@@ -5,7 +5,7 @@ use irtt_proto::{Params, TimestampFields};
use support::{
config_for_params, default_params, run_one_probe, run_one_probe_with_config, server_fill,
start_open_server, OneProbeRun, ServerObservation,
start_open_server, InTreeServer, OneProbeRun, ServerObservation,
};
use crate::support::test_echo_packet_len;
@@ -68,8 +68,21 @@ fn server_fill_empty_and_oversized_values_are_rejected_at_config_boundary() {
fn server_fill_negotiated_params_reflect_accepted_value() {
let mut params = default_params();
params.server_fill = server_fill("rand");
let run = run_one_probe(params.clone(), TimestampFields::default());
assert_eq!(run.negotiated.params.server_fill, params.server_fill);
let server = InTreeServer::start(irtt_server::ServerConfig::default());
let mut client = Client::connect(config_for_params(server.addr, &params)).unwrap();
let outcome = client.open().unwrap();
let negotiated = match outcome {
irtt_client::OpenOutcome::Started { negotiated, .. } => negotiated,
other => panic!("expected started outcome, got {other:?}"),
};
assert_eq!(negotiated.params.server_fill, params.server_fill);
client.send_probe().unwrap();
assert!(matches!(
client.recv_once().unwrap().as_slice(),
[irtt_client::ClientEvent::EchoReply { .. }]
));
client.close().unwrap();
}
#[test]
@@ -0,0 +1,99 @@
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<(), String>>>,
}
impl InTreeServer {
pub fn start(config: ServerConfig) -> 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()
.map_err(|error| format!("failed to build test server runtime: {error}"))?;
runtime.block_on(async move {
let bind_addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::LOCALHOST), 0);
let mut server = match 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
.send(Ok(addr))
.map_err(|_| "test stopped waiting for in-tree server startup".to_owned())?;
server
.run(async {
let _ = shutdown_rx.await;
})
.await
.map_err(|error| format!("in-tree test server failed: {error}"))
})
});
let addr = match startup_rx.recv_timeout(STARTUP_TIMEOUT) {
Ok(Ok(addr)) => addr,
Ok(Err(error)) => {
done.join()
.expect("in-tree test server thread panicked")
.ok();
panic!("{error}");
}
Err(error) => {
let _ = shutdown_tx.send(());
done.join()
.expect("in-tree test server thread panicked")
.ok();
panic!("timed out waiting for in-tree test server startup: {error}");
}
};
Self {
addr,
shutdown: Some(shutdown_tx),
done: Some(done),
}
}
fn stop_inner(&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_inner();
}
}
+17 -14
View File
@@ -1,5 +1,6 @@
#![allow(dead_code)]
mod in_tree_server;
mod real_irtt;
use std::{
@@ -17,7 +18,9 @@ use irtt_proto::{
PacketLayout, Params, ProtoError, ReceivedStats, ServerFill, StampAt, TimestampFields,
HMAC_SIZE, MAGIC, PROTOCOL_VERSION,
};
use irtt_server::ServerConfig;
pub use in_tree_server::InTreeServer;
pub use real_irtt::RealIrtServer;
const HMAC_OFFSET: usize = 4;
@@ -27,7 +30,7 @@ pub const RECV_WINDOW: u64 = 0x07;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum TestBackendKind {
Fake,
InTree,
Real,
}
@@ -43,9 +46,9 @@ pub fn selected_backend() -> TestBackendKind {
_ => panic!("IRTT_TEST_BACKEND=real but irtt binary not found at '{irtt_bin}'"),
}
}
Ok("fake") | Err(_) => {
debug_backend("[backend] selected backend=fake");
TestBackendKind::Fake
Ok("in-tree") | Err(_) => {
debug_backend("[backend] selected backend=in-tree");
TestBackendKind::InTree
}
Ok(other) => panic!("unknown IRTT_TEST_BACKEND value: {other}"),
}
@@ -58,24 +61,25 @@ fn debug_backend(message: &str) {
}
pub enum BackendPeer {
Fake(FakeServer),
InTree(InTreeServer),
Real(RealIrtServer),
}
impl BackendPeer {
pub fn addr(&self) -> SocketAddr {
match self {
BackendPeer::Fake(s) => s.addr,
BackendPeer::InTree(s) => s.addr,
BackendPeer::Real(s) => s.addr(),
}
}
pub fn start_open_echo(params: Params, hmac_key: Option<Vec<u8>>) -> Self {
pub fn start_open_echo(hmac_key: Option<Vec<u8>>) -> Self {
match selected_backend() {
TestBackendKind::Fake => {
let timestamps = standard_timestamps();
BackendPeer::Fake(start_one_probe_server(params, timestamps, hmac_key))
}
TestBackendKind::InTree => BackendPeer::InTree(InTreeServer::start(
hmac_key.map_or_else(ServerConfig::default, |key| {
ServerConfig::default().with_hmac_key(key)
}),
)),
TestBackendKind::Real => {
BackendPeer::Real(RealIrtServer::start(hmac_key.as_deref()).unwrap())
}
@@ -84,9 +88,8 @@ impl BackendPeer {
pub fn start_hmac_required(key: Vec<u8>) -> Self {
match selected_backend() {
TestBackendKind::Fake => BackendPeer::Fake(start_hmac_required_open_drop_server(
key,
Duration::from_millis(250),
TestBackendKind::InTree => BackendPeer::InTree(InTreeServer::start(
ServerConfig::default().with_hmac_key(key),
)),
TestBackendKind::Real => BackendPeer::Real(RealIrtServer::start(Some(&key)).unwrap()),
}