fix(tests): break the irtt-client/irtt-server dev-dependency cycle
irtt-client and irtt-server mutually dev-depended on each other for cross-crate integration tests. That cycle blocks `cargo publish` for either crate whenever the other doesn't already exist on the registry at the required version, which is exactly the situation for a crate's first-ever release (irtt-server has never been published before). Introduce a new `irtt-integration-tests` crate (publish = false, no library target) to own tests whose actual subject is the interaction between two or more irtt-* production crates: crate-local behavior -> crate's own tests/ cross-crate/system behavior -> irtt-integration-tests Move every test that imports both irtt_client and irtt_server there: the client-side support harness (hmac, large_packets, protocol_options, fill_negotiation) and the server-side real-socket tests that drive a real AsyncClient against a real Server (async_client, negotiation_policy, fill_wire_bytes, traffic_class, wildcard_source). server_set.rs stays in irtt-server/tests since it only uses irtt_proto as test machinery to drive irtt-server directly, which is a normal one-directional test dependency, not a peer relationship. irtt-server's dev-dependency on irtt-client is dropped entirely now that nothing under crates/irtt-server/tests needs it, which fully breaks the cycle from that side. irtt-client keeps a one-directional dev-dependency on irtt-server: a handful of white-box unit tests in src/async_client/tests.rs assert on private AsyncClient internals (socket, remote, test_hooks) while also needing a real in-tree server for blocking/async equivalence checks, so they can't move to an external crate without losing that access. Their InTreeServer helper is duplicated locally rather than shared, matching the existing precedent of irtt-cli's own tests/support/in_tree_server.rs.
This commit is contained in:
19 files changed
+106
-5
No files matched your search
Generated
+10
-1
@@ -719,6 +719,16 @@ dependencies = [
|
|||||||
"tokio",
|
"tokio",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "irtt-integration-tests"
|
||||||
|
version = "0.0.0"
|
||||||
|
dependencies = [
|
||||||
|
"irtt-client",
|
||||||
|
"irtt-proto",
|
||||||
|
"irtt-server",
|
||||||
|
"tokio",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "irtt-proto"
|
name = "irtt-proto"
|
||||||
version = "0.5.0"
|
version = "0.5.0"
|
||||||
@@ -734,7 +744,6 @@ name = "irtt-server"
|
|||||||
version = "0.5.0"
|
version = "0.5.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"getrandom 0.4.3",
|
"getrandom 0.4.3",
|
||||||
"irtt-client",
|
|
||||||
"irtt-proto",
|
"irtt-proto",
|
||||||
"nix 0.31.3",
|
"nix 0.31.3",
|
||||||
"socket2",
|
"socket2",
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ members = [
|
|||||||
"crates/irtt-server",
|
"crates/irtt-server",
|
||||||
"crates/irtt-stats",
|
"crates/irtt-stats",
|
||||||
"crates/irtt-cli",
|
"crates/irtt-cli",
|
||||||
|
"crates/irtt-integration-tests",
|
||||||
]
|
]
|
||||||
resolver = "2"
|
resolver = "2"
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,82 @@
|
|||||||
|
//! A real `irtt-server` running in-process, for tests that need to prove
|
||||||
|
//! `AsyncClient` and the blocking `Client` are equivalent against a real peer.
|
||||||
|
//!
|
||||||
|
//! This duplicates `crates/irtt-integration-tests/tests/support/in_tree_server.rs`
|
||||||
|
//! rather than depending on it: this module backs private (`super::*`) unit
|
||||||
|
//! tests here, while the integration crate covers black-box client/server
|
||||||
|
//! behavior, and neither can depend on the other's test-only code.
|
||||||
|
|
||||||
|
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(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()
|
||||||
|
.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, config).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_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();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -14,7 +14,7 @@ use irtt_proto::{
|
|||||||
};
|
};
|
||||||
use tokio::runtime::{Builder, Runtime};
|
use tokio::runtime::{Builder, Runtime};
|
||||||
|
|
||||||
#[path = "../../tests/support/in_tree_server.rs"]
|
#[path = "in_tree_server_support.rs"]
|
||||||
mod in_tree_server;
|
mod in_tree_server;
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|||||||
@@ -0,0 +1,12 @@
|
|||||||
|
[package]
|
||||||
|
name = "irtt-integration-tests"
|
||||||
|
version = "0.0.0"
|
||||||
|
edition.workspace = true
|
||||||
|
rust-version.workspace = true
|
||||||
|
publish = false
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
irtt-client = { workspace = true, features = ["ancillary", "tokio"] }
|
||||||
|
irtt-server.workspace = true
|
||||||
|
irtt-proto.workspace = true
|
||||||
|
tokio = { version = "1.53.1", default-features = false, features = ["rt", "net", "time", "sync", "macros"] }
|
||||||
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
@@ -23,6 +23,3 @@ tokio = { version = "1.53.1", default-features = false, features = ["rt", "net",
|
|||||||
# source-selection path here; elsewhere a wildcard bind is refused.
|
# source-selection path here; elsewhere a wildcard bind is refused.
|
||||||
[target.'cfg(any(target_os = "linux", target_os = "macos", target_os = "freebsd"))'.dependencies]
|
[target.'cfg(any(target_os = "linux", target_os = "macos", target_os = "freebsd"))'.dependencies]
|
||||||
nix = { version = "0.31.3", default-features = false, features = ["net", "uio"] }
|
nix = { version = "0.31.3", default-features = false, features = ["net", "uio"] }
|
||||||
|
|
||||||
[dev-dependencies]
|
|
||||||
irtt-client = { workspace = true, features = ["ancillary", "tokio"] }
|
|
||||||
Reference in new issue
Block a user