diff --git a/Cargo.lock b/Cargo.lock index cf4ab07e..e44b0ec9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3549,6 +3549,16 @@ dependencies = [ "serde", ] +[[package]] +name = "socket2" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3d1e2c7f27f8d4cb10542a02c49005dbd6e93095799d6f3be745fae9f8fedd4" +dependencies = [ + "libc", + "windows-sys 0.61.2", +] + [[package]] name = "spirv" version = "0.4.0+sdk-1.4.341.0" @@ -4194,6 +4204,7 @@ dependencies = [ "log", "proptest", "serde_json", + "socket2", "vectorcraft-doc", "vectorcraft-engine", "vectorcraft-format", diff --git a/Cargo.toml b/Cargo.toml index 9f086091..a6995419 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -38,6 +38,8 @@ serde = { version = "1", features = ["derive", "rc"] } serde_json = { version = "1", features = ["float_roundtrip"] } log = "0.4" proptest = "1" +# tests: a TCP port bound without listening (connections to it are refused) +socket2 = "0.6" # rendering / formats vello_cpu = "0.2" diff --git a/crates/mcp/Cargo.toml b/crates/mcp/Cargo.toml index dc30eb7d..34fdafef 100644 --- a/crates/mcp/Cargo.toml +++ b/crates/mcp/Cargo.toml @@ -23,3 +23,4 @@ log = { workspace = true } vectorcraft-testkit = { workspace = true } proptest = { workspace = true } image = { workspace = true } +socket2 = { workspace = true } diff --git a/crates/mcp/src/tests.rs b/crates/mcp/src/tests.rs index 2e2c4f6a..37c091d9 100644 --- a/crates/mcp/src/tests.rs +++ b/crates/mcp/src/tests.rs @@ -377,9 +377,17 @@ fn remote_forwards_methods() { #[test] fn remote_connect_fails_fast() { - // Bind then drop to get a port that's (almost certainly) closed. - let port = std::net::TcpListener::bind("127.0.0.1:0").unwrap().local_addr().unwrap().port(); + // A port this test holds, bound but not listening, so connecting to it is refused. (A port + // bound and dropped could be taken by another process or test before the connect.) + let held = socket2::Socket::new(socket2::Domain::IPV4, socket2::Type::STREAM, None).unwrap(); + held.bind(&std::net::SocketAddr::from(([127, 0, 0, 1], 0)).into()).unwrap(); + let port = held.local_addr().unwrap().as_socket().unwrap().port(); + let start = std::time::Instant::now(); assert!(Remote::connect(&format!("127.0.0.1:{port}")).is_err()); + assert!(start.elapsed() < std::time::Duration::from_secs(5), "took {:?}", start.elapsed()); + // Nothing else could listen there meanwhile. + assert!(std::net::TcpListener::bind(format!("127.0.0.1:{port}")).is_err()); + drop(held); } #[test]