Skip to content

Commit

Permalink
Add some basic unit test for QUIC ping client. (#55)
Browse files Browse the repository at this point in the history
  • Loading branch information
r12f authored Jul 26, 2021
1 parent 857f935 commit 2d0e4c1
Show file tree
Hide file tree
Showing 4 changed files with 75 additions and 15 deletions.
45 changes: 43 additions & 2 deletions src/ping_clients/ping_client_quic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -109,15 +109,17 @@ impl PingClientQuic {
let connection = match connecting_result {
Ok(connection) => Ok(connection),
Err(e) => match e {
ConnectionError::TimedOut => Err(PingClientError::PingFailed(Box::new(e))),
ConnectionError::TimedOut => {
return Ok(PingClientPingResultDetails::new(None, rtt, true, None));
},
ConnectionError::LocallyClosed => Err(PingClientError::PingFailed(Box::new(e))),
_ => {
return Ok(PingClientPingResultDetails::new(
None,
rtt,
false,
Some(PingClientWarning::AppHandshakeFailed(Box::new(e))),
))
));
}
},
}?;
Expand Down Expand Up @@ -161,3 +163,42 @@ impl rustls::ServerCertVerifier for SkipCertificationVerification {
Ok(ServerCertVerified::assertion())
}
}

#[cfg(test)]
mod tests {
use crate::ping_clients::ping_client_test_common::*;
use crate::{ping_clients::ping_client_factory, PingClientConfig, RnpSupportedProtocol, rnp_test_common};
use std::time::Duration;
use tokio::runtime::Runtime;

#[test]
fn ping_client_quic_should_work() {
rnp_test_common::initialize();

let rt = Runtime::new().unwrap();

rt.block_on(async {
let config = PingClientConfig {
wait_timeout: Duration::from_millis(300),
time_to_live: None,
check_disconnect: false,
server_name: Some("localhost".to_string()),
log_tls_key: false,
alpn_protocol: Some("hq-29".to_string()),
use_timer_rtt: false,
};
let mut ping_client = ping_client_factory::new(&RnpSupportedProtocol::QUIC, &config, None);

// When connecting to a non existing port, on windows, it will timeout, but on other *nix OS, it will reject the connection.
let expected_results = ExpectedPingClientTestResults {
timeout_min_time: Duration::from_millis(200),
ping_non_existing_host_result: ExpectedTestCaseResult::Timeout,
ping_non_existing_port_result: ExpectedTestCaseResult::Timeout,
binding_invalid_source_ip_result: ExpectedTestCaseResult::Failed("failed to set up UDP socket: The requested address is not valid in its context. (os error 10049)"),
binding_unavailable_source_port_result: ExpectedTestCaseResult::Failed("failed to set up UDP socket: Only one usage of each socket address (protocol/network address/port) is normally permitted. (os error 10048)"),
};

run_ping_client_tests(&mut ping_client, &"127.0.0.1:4433".parse().unwrap(), &expected_results).await;
});
}
}
2 changes: 1 addition & 1 deletion src/ping_clients/ping_client_tcp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,7 @@ mod tests {
binding_unavailable_source_port_result: ExpectedTestCaseResult::Failed("Only one usage of each socket address (protocol/network address/port) is normally permitted. (os error 10048)"),
};

run_ping_client_tests(&mut ping_client, &expected_results).await;
run_ping_client_tests(&mut ping_client, &"127.0.0.1:11337".parse().unwrap(), &expected_results).await;
});
}

Expand Down
25 changes: 18 additions & 7 deletions src/ping_clients/ping_client_test_common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,26 +19,33 @@ pub struct ExpectedPingClientTestResults {

pub async fn run_ping_client_tests(
ping_client: &mut Box<dyn PingClient + Send + Sync>,
mock_server_addr: &SocketAddr,
expected_results: &ExpectedPingClientTestResults,
) {
// TODO: This is failing on Linux and MAC, need to figure out why.
if cfg!(windows) {
ping_client_should_work_when_pinging_good_host(ping_client, expected_results).await;
if ping_client.protocol() != "QUIC" {
ping_client_should_work_when_pinging_good_host(ping_client, mock_server_addr, expected_results).await;
}

ping_client_should_fail_when_pinging_non_existing_host(ping_client, expected_results).await;
ping_client_should_fail_when_pinging_non_existing_port(ping_client, expected_results).await;
ping_client_should_fail_when_binding_invalid_source_ip(ping_client, expected_results).await;
ping_client_should_fail_when_binding_unavailable_source_port(ping_client, expected_results)
.await;

if ping_client.protocol() != "QUIC" {
ping_client_should_fail_when_binding_unavailable_source_port(ping_client, mock_server_addr, expected_results).await;
}
}

async fn ping_client_should_work_when_pinging_good_host(
ping_client: &mut Box<dyn PingClient + Send + Sync>,
mock_server_addr: &SocketAddr,
expected_results: &ExpectedPingClientTestResults,
) {
let target = mock_server_addr.clone();
if target.port() == 0 {
return;
}

let source = "0.0.0.0:0".parse::<SocketAddr>().unwrap();
let target = "127.0.0.1:3389".parse::<SocketAddr>().unwrap();
ping_client_result_should_be_expected(
ping_client,
&source,
Expand Down Expand Up @@ -99,9 +106,10 @@ async fn ping_client_should_fail_when_binding_invalid_source_ip(

async fn ping_client_should_fail_when_binding_unavailable_source_port(
ping_client: &mut Box<dyn PingClient + Send + Sync>,
mock_server_addr: &SocketAddr,
expected_results: &ExpectedPingClientTestResults,
) {
let source = "127.0.0.1:11337".parse::<SocketAddr>().unwrap();
let source = mock_server_addr.clone();
let target = "127.0.0.1:56789".parse::<SocketAddr>().unwrap();
ping_client_result_should_be_expected(
ping_client,
Expand All @@ -121,6 +129,9 @@ async fn ping_client_result_should_be_expected(
expected_error: &ExpectedTestCaseResult,
) {
let actual_result = ping_client.ping(source, target).await;
let ping_result_string = format!("Ping result: {:?}", actual_result);
tracing::info!("{}", ping_result_string);

match expected_error {
ExpectedTestCaseResult::Ok => {
assert!(actual_result.is_ok());
Expand Down
18 changes: 13 additions & 5 deletions src/rnp_test_common.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,17 @@
use crate::ping_clients::ping_client::PingClientError::{PingFailed, PreparationFailed};
use crate::ping_clients::ping_client::PingClientWarning;
use crate::ping_result::PingResult;
use crate::*;
use chrono::{TimeZone, Utc};
use std::io;
use std::time::Duration;
use std::sync::Once;

static INIT: Once = Once::new();

pub fn initialize() {
INIT.call_once(|| {
// initialization code here
let _ = env_logger::builder().is_test(true).try_init();
});
}

pub fn generate_ping_result_test_samples() -> Vec<PingResult> {
vec![
Expand Down Expand Up @@ -79,7 +87,7 @@ pub fn generate_ping_result_test_samples() -> Vec<PingResult> {
Duration::from_millis(0),
false,
None,
Some(PingFailed(Box::new(io::Error::new(
Some(PingClientError::PingFailed(Box::new(io::Error::new(
io::ErrorKind::ConnectionRefused,
"connect failed",
)))),
Expand All @@ -96,7 +104,7 @@ pub fn generate_ping_result_test_samples() -> Vec<PingResult> {
Duration::from_millis(0),
false,
None,
Some(PreparationFailed(Box::new(io::Error::new(
Some(PingClientError::PreparationFailed(Box::new(io::Error::new(
io::ErrorKind::AddrInUse,
"address in use",
)))),
Expand Down

0 comments on commit 2d0e4c1

Please sign in to comment.