diff --git a/src/net.rs b/src/net.rs index 01cf1c03c6..37685d72ea 100644 --- a/src/net.rs +++ b/src/net.rs @@ -157,7 +157,8 @@ pub(crate) async fn connect_tls_inner( /// and runs them until one of them succeeds /// or all of them fail. /// -/// If all connection attempts fail, returns the first error. +/// If all connection attempts fail, returns an error +/// that includes the reasons for all failures. /// /// This functions starts with one connection attempt and maintains /// up to five parallel connection attempts if connecting takes time. @@ -209,6 +210,9 @@ where } } None => { + // We should never return an error with connection attempts left to try. + debug_assert!(futures.next().is_none()); + // Out of connection attempts. // // Break out of the loop and return error. @@ -261,3 +265,43 @@ pub(crate) async fn connect_tcp( .map(connect_tcp_inner); run_connection_attempts(connection_futures).await } + +#[cfg(test)] +mod tests { + use super::*; + + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] + async fn test_run_connection_attempts() { + let futures: Vec> + Send>>> = + vec![Box::pin(async { Ok(1) }), Box::pin(async { Ok(2) })]; + assert_eq!( + run_connection_attempts(futures.into_iter()).await.unwrap(), + 1 + ); + + let futures: Vec> + Send>>> = vec![ + Box::pin(async { Err(format_err!("fail")) }), + Box::pin(async { Ok(2) }), + ]; + assert_eq!( + run_connection_attempts(futures.into_iter()).await.unwrap(), + 2 + ); + + let futures: Vec> + Send>>> = vec![ + Box::pin(async { Err(format_err!("fail")) }), + Box::pin(async { Err(format_err!("fail")) }), + Box::pin(async { Err(format_err!("fail")) }), + Box::pin(async { Err(format_err!("fail")) }), + Box::pin(async { Err(format_err!("fail")) }), + Box::pin(async { Err(format_err!("last")) }), + ]; + assert!( + run_connection_attempts(futures.into_iter()) + .await + .unwrap_err() + .to_string() + .contains("last"), + ); + } +}