use std::{
net::{IpAddr, Ipv4Addr, SocketAddr},
sync::Arc,
time::Duration,
};
use proptest::{
collection::vec,
prelude::{Strategy, any},
prop_assert,
};
use test_strategy::proptest;
use tracing::error;
use crate::{
ClientConfig, Connection, ConnectionClose, ConnectionError, Event, PathStatus, Side,
TransportConfig, TransportErrorCode,
tests::{
Pair, RoutingTable, client_config,
random_interaction::{TestOp, run_random_interaction},
server_config, subscribe,
},
};
const MAX_MULTIPATH_PATHS: u32 = 13;
const MAX_QNT_ADDRS: u8 = 12;
const PATH_MAX_IDLE_TIMEOUT: Duration = Duration::from_secs(15);
const HEARTBEAT_INTERVAL: Duration = Duration::from_secs(5);
const CLIENT_PORT: u16 = 44433;
const SERVER_PORT: u16 = 4433;
const CLIENT_ADDRS: [SocketAddr; 3] = [
SocketAddr::new(
IpAddr::V6(Ipv4Addr::new(1, 1, 1, 0).to_ipv6_mapped()),
CLIENT_PORT,
),
SocketAddr::new(
IpAddr::V6(Ipv4Addr::new(1, 1, 1, 1).to_ipv6_mapped()),
CLIENT_PORT,
),
SocketAddr::new(
IpAddr::V6(Ipv4Addr::new(1, 1, 1, 2).to_ipv6_mapped()),
CLIENT_PORT,
),
];
const SERVER_ADDRS: [SocketAddr; 3] = [
SocketAddr::new(
IpAddr::V6(Ipv4Addr::new(2, 2, 2, 0).to_ipv6_mapped()),
SERVER_PORT,
),
SocketAddr::new(
IpAddr::V6(Ipv4Addr::new(2, 2, 2, 1).to_ipv6_mapped()),
SERVER_PORT,
),
SocketAddr::new(
IpAddr::V6(Ipv4Addr::new(2, 2, 2, 2).to_ipv6_mapped()),
SERVER_PORT,
),
];
#[derive(Debug, test_strategy::Arbitrary)]
struct PairSetup {
seed: Seed,
extensions: Extensions,
routing_setup: RoutingSetup,
}
#[derive(Debug, test_strategy::Arbitrary)]
enum Extensions {
None,
MultipathOnly,
QntAndMultipath,
}
#[derive(Debug, test_strategy::Arbitrary)]
enum RoutingSetup {
None,
SimpleSymmetric,
Complex(#[strategy(routing_table())] RoutingTable),
}
#[derive(Debug, test_strategy::Arbitrary)]
enum Seed {
Zeroes,
Generated(#[strategy(any::<[u8; 32]>().no_shrink())] [u8; 32]),
}
impl PairSetup {
fn run(self, prefix: &'static str) -> (Pair, ClientConfig) {
let mut pair = Pair::seeded(self.seed.into_slice());
let mut transport = TransportConfig::default();
#[cfg(feature = "qlog")]
transport.qlog_from_env(prefix);
#[cfg(not(feature = "qlog"))]
let _ = prefix;
if self.extensions.is_multipath_enabled() {
transport.max_concurrent_multipath_paths(MAX_MULTIPATH_PATHS);
transport.default_path_max_idle_timeout(Some(PATH_MAX_IDLE_TIMEOUT));
transport.default_path_keep_alive_interval(Some(HEARTBEAT_INTERVAL));
}
if self.extensions.is_qnt_enabled() {
transport.set_max_remote_nat_traversal_addresses(MAX_QNT_ADDRS);
}
let mut server_cfg = server_config();
server_cfg.transport = Arc::new(transport.clone());
pair.server
.endpoint
.set_server_config(Some(Arc::new(server_cfg)));
let mut client_cfg = client_config();
client_cfg.transport = Arc::new(transport);
match self.routing_setup {
RoutingSetup::None => {
pair.routes = None;
}
RoutingSetup::SimpleSymmetric => {
let routes = RoutingTable::simple_symmetric(CLIENT_ADDRS, SERVER_ADDRS);
pair.client.addr = routes.client_addr(0).unwrap();
pair.server.addr = routes.server_addr(0).unwrap();
pair.routes = Some(routes);
}
RoutingSetup::Complex(routes) => {
pair.client.addr = routes.client_addr(0).unwrap();
pair.server.addr = routes.server_addr(0).unwrap();
pair.routes = Some(routes);
}
}
(pair, client_cfg)
}
}
impl Extensions {
fn is_multipath_enabled(&self) -> bool {
matches!(self, Self::MultipathOnly | Self::QntAndMultipath)
}
fn is_qnt_enabled(&self) -> bool {
matches!(self, Self::QntAndMultipath)
}
}
impl Seed {
fn into_slice(self) -> [u8; 32] {
match self {
Self::Zeroes => [0u8; 32],
Self::Generated(generated) => generated,
}
}
}
#[proptest(cases = 256)]
fn random_interaction(
setup: PairSetup,
#[strategy(vec(any::<TestOp>(), 0..100))] interactions: Vec<TestOp>,
) {
let (mut pair, client_config) = setup.run("random_interaction");
let (client_ch, server_ch) = run_random_interaction(&mut pair, interactions, client_config);
prop_assert!(!pair.drive_bounded(1000), "connection never became idle");
prop_assert!(allowed_error(poll_to_close(
pair.client_conn_mut(client_ch)
)));
prop_assert!(allowed_error(poll_to_close(
pair.server_conn_mut(server_ch)
)));
}
fn routing_table() -> impl Strategy<Value = RoutingTable> {
(vec(0..=5usize, 0..=4), vec(0..=5usize, 0..=4)).prop_map(|(client_offsets, server_offsets)| {
let mut client_addr = SocketAddr::new(
IpAddr::V6(Ipv4Addr::new(1, 1, 1, 0).to_ipv6_mapped()),
CLIENT_PORT,
);
let mut server_addr = SocketAddr::new(
IpAddr::V6(Ipv4Addr::new(2, 2, 2, 0).to_ipv6_mapped()),
SERVER_PORT,
);
let mut client_routes = vec![(client_addr, 0)];
let mut server_routes = vec![(server_addr, 0)];
for (idx, &offset) in client_offsets.iter().enumerate() {
let other_idx = idx.saturating_sub(offset);
let server_idx = other_idx.clamp(0, server_offsets.len());
client_addr.set_ip(IpAddr::V6(
Ipv4Addr::new(1, 1, 1, idx as u8 + 1).to_ipv6_mapped(),
));
client_routes.push((client_addr, server_idx));
}
for (idx, &offset) in server_offsets.iter().enumerate() {
let other_idx = idx.saturating_sub(offset);
let client_idx = other_idx.clamp(0, client_offsets.len());
server_addr.set_ip(IpAddr::V6(
Ipv4Addr::new(2, 2, 2, idx as u8 + 1).to_ipv6_mapped(),
));
server_routes.push((server_addr, client_idx));
}
RoutingTable::from_routes(client_routes, server_routes)
})
}
fn old_routing_table() -> RoutingTable {
let mut routes = RoutingTable::simple_symmetric([CLIENT_ADDRS[0]], [SERVER_ADDRS[0]]);
for addr in CLIENT_ADDRS.into_iter().skip(1) {
routes.add_client_route(addr, 0);
}
for addr in SERVER_ADDRS.into_iter().skip(1) {
routes.add_server_route(addr, 0);
}
routes
}
fn allowed_error(err: Option<ConnectionError>) -> bool {
let allowed = match &err {
None => true,
Some(ConnectionError::TransportError(err)) => {
&err.reason == "last path abandoned, no new path opened"
}
Some(ConnectionError::ConnectionClosed(ConnectionClose { error_code, .. })) => {
*error_code != TransportErrorCode::PROTOCOL_VIOLATION
}
_ => true,
};
if !allowed {
error!(
?err,
"Got an error that's unexpected in noq <-> noq interaction"
);
}
allowed
}
fn poll_to_close(conn: &mut Connection) -> Option<ConnectionError> {
let mut close = None;
while let Some(event) = conn.poll() {
if let Event::ConnectionLost { reason } = event {
close = Some(reason);
}
}
close
}
#[test]
fn regression_unset_packet_acked() {
let prefix = "regression_unset_packet_acked";
let setup = PairSetup {
seed: Seed::Generated([
60, 116, 60, 165, 136, 238, 239, 131, 14, 159, 221, 16, 80, 60, 30, 15, 15, 69, 133,
33, 89, 203, 28, 107, 123, 117, 6, 54, 215, 244, 47, 1,
]),
extensions: Extensions::MultipathOnly,
routing_setup: RoutingSetup::Complex(old_routing_table()),
};
let interactions = vec![
TestOp::OpenPath {
side: Side::Client,
status: PathStatus::Available,
addr_idx: 0,
},
TestOp::ClosePath {
side: Side::Client,
path_idx: 0,
error_code: 0,
},
TestOp::Drive { side: Side::Client },
TestOp::AdvanceTime,
TestOp::Drive { side: Side::Server },
TestOp::DropInbound { side: Side::Client },
];
let _guard = subscribe();
let (mut pair, client_config) = setup.run(prefix);
let (client_ch, server_ch) = run_random_interaction(&mut pair, interactions, client_config);
assert!(!pair.drive_bounded(1000), "connection never became idle");
assert!(allowed_error(poll_to_close(
pair.client_conn_mut(client_ch)
)));
assert!(allowed_error(poll_to_close(
pair.server_conn_mut(server_ch)
)));
}
#[test]
fn regression_invalid_key() {
let prefix = "regression_invalid_key";
let setup = PairSetup {
seed: Seed::Generated([
41, 24, 232, 72, 136, 73, 31, 115, 14, 101, 61, 219, 30, 168, 130, 122, 120, 238, 6,
130, 117, 84, 250, 190, 50, 237, 14, 167, 60, 5, 140, 149,
]),
extensions: Extensions::MultipathOnly,
routing_setup: RoutingSetup::Complex(old_routing_table()),
};
let interactions = vec![
TestOp::OpenPath {
side: Side::Client,
status: PathStatus::Available,
addr_idx: 0,
},
TestOp::AdvanceTime,
TestOp::Drive { side: Side::Client },
TestOp::OpenPath {
side: Side::Client,
status: PathStatus::Available,
addr_idx: 0,
},
];
let _guard = subscribe();
let (mut pair, client_config) = setup.run(prefix);
let (client_ch, server_ch) = run_random_interaction(&mut pair, interactions, client_config);
assert!(!pair.drive_bounded(1000), "connection never became idle");
assert!(allowed_error(poll_to_close(
pair.client_conn_mut(client_ch)
)));
assert!(allowed_error(poll_to_close(
pair.server_conn_mut(server_ch)
)));
}
#[test]
fn regression_invalid_key2() {
let prefix = "regression_invalid_key2";
let setup = PairSetup {
seed: Seed::Zeroes,
extensions: Extensions::MultipathOnly,
routing_setup: RoutingSetup::SimpleSymmetric,
};
let interactions = vec![
TestOp::CloseConn {
side: Side::Client,
error_code: 0,
},
TestOp::AdvanceTime,
TestOp::Drive { side: Side::Client },
TestOp::OpenPath {
side: Side::Client,
status: PathStatus::Available,
addr_idx: 0,
},
TestOp::ClosePath {
side: Side::Client,
path_idx: 0,
error_code: 0,
},
];
let _guard = subscribe();
let (mut pair, client_config) = setup.run(prefix);
let (client_ch, server_ch) = run_random_interaction(&mut pair, interactions, client_config);
assert!(!pair.drive_bounded(1000), "connection never became idle");
assert!(allowed_error(poll_to_close(
pair.client_conn_mut(client_ch)
)));
assert!(allowed_error(poll_to_close(
pair.server_conn_mut(server_ch)
)));
}
#[test]
fn regression_key_update_error() {
let prefix = "regression_key_update_error";
let setup = PairSetup {
seed: Seed::Generated([
68, 93, 15, 237, 88, 31, 93, 255, 246, 51, 203, 224, 20, 124, 107, 163, 143, 43, 193,
187, 208, 54, 158, 239, 190, 82, 198, 62, 91, 51, 53, 226,
]),
extensions: Extensions::MultipathOnly,
routing_setup: RoutingSetup::Complex(old_routing_table()),
};
let interactions = vec![
TestOp::OpenPath {
side: Side::Client,
status: PathStatus::Available,
addr_idx: 0,
},
TestOp::Drive { side: Side::Client },
TestOp::ForceKeyUpdate { side: Side::Server },
];
let _guard = subscribe();
let (mut pair, client_config) = setup.run(prefix);
let (client_ch, server_ch) = run_random_interaction(&mut pair, interactions, client_config);
assert!(!pair.drive_bounded(1000), "connection never became idle");
assert!(allowed_error(poll_to_close(
pair.client_conn_mut(client_ch)
)));
assert!(allowed_error(poll_to_close(
pair.server_conn_mut(server_ch)
)));
}
#[test]
fn regression_never_idle() {
let prefix = "regression_never_idle";
let setup = PairSetup {
seed: Seed::Zeroes,
extensions: Extensions::MultipathOnly,
routing_setup: RoutingSetup::Complex(old_routing_table()),
};
let interactions = vec![
TestOp::OpenPath {
side: Side::Client,
status: PathStatus::Available,
addr_idx: 1,
},
TestOp::PathSetStatus {
side: Side::Server,
path_idx: 0,
status: PathStatus::Backup,
},
TestOp::ClosePath {
side: Side::Client,
path_idx: 0,
error_code: 0,
},
];
let _guard = subscribe();
let (mut pair, client_config) = setup.run(prefix);
let (client_ch, server_ch) = run_random_interaction(&mut pair, interactions, client_config);
assert!(!pair.drive_bounded(1000), "connection never became idle");
assert!(allowed_error(poll_to_close(
pair.client_conn_mut(client_ch)
)));
assert!(allowed_error(poll_to_close(
pair.server_conn_mut(server_ch)
)));
}
#[test]
fn regression_never_idle2() {
let prefix = "regression_never_idle2";
let setup = PairSetup {
seed: Seed::Zeroes,
extensions: Extensions::MultipathOnly,
routing_setup: RoutingSetup::Complex(old_routing_table()),
};
let interactions = vec![
TestOp::OpenPath {
side: Side::Client,
status: PathStatus::Backup,
addr_idx: 1,
},
TestOp::ClosePath {
side: Side::Client,
path_idx: 0,
error_code: 0,
},
TestOp::Drive { side: Side::Client },
TestOp::DropInbound { side: Side::Server },
TestOp::PathSetStatus {
side: Side::Client,
path_idx: 0,
status: PathStatus::Available,
},
];
let _guard = subscribe();
let (mut pair, client_config) = setup.run(prefix);
let (client_ch, server_ch) = run_random_interaction(&mut pair, interactions, client_config);
assert!(!pair.drive_bounded(1000), "connection never became idle");
assert!(allowed_error(poll_to_close(
pair.client_conn_mut(client_ch)
)));
assert!(allowed_error(poll_to_close(
pair.server_conn_mut(server_ch)
)));
}
#[test]
fn regression_packet_number_space_missing() {
let prefix = "regression_packet_number_space_missing";
let setup = PairSetup {
seed: Seed::Zeroes,
extensions: Extensions::MultipathOnly,
routing_setup: RoutingSetup::SimpleSymmetric,
};
let interactions = vec![
TestOp::OpenPath {
side: Side::Client,
status: PathStatus::Backup,
addr_idx: 0,
},
TestOp::OpenPath {
side: Side::Client,
status: PathStatus::Backup,
addr_idx: 0,
},
TestOp::Drive { side: Side::Client },
TestOp::DropInbound { side: Side::Server },
TestOp::ClosePath {
side: Side::Client,
path_idx: 0,
error_code: 0,
},
];
let _guard = subscribe();
let (mut pair, client_config) = setup.run(prefix);
let (client_ch, server_ch) = run_random_interaction(&mut pair, interactions, client_config);
assert!(!pair.drive_bounded(1000), "connection never became idle");
assert!(allowed_error(poll_to_close(
pair.client_conn_mut(client_ch)
)));
assert!(allowed_error(poll_to_close(
pair.server_conn_mut(server_ch)
)));
}
#[test]
fn regression_peer_failed_to_respond_with_path_abandon() {
let prefix = "regression_peer_failed_to_respond_with_path_abandon";
let setup = PairSetup {
seed: Seed::Zeroes,
extensions: Extensions::MultipathOnly,
routing_setup: RoutingSetup::Complex(old_routing_table()),
};
let interactions = vec![
TestOp::OpenPath {
side: Side::Client,
status: PathStatus::Available,
addr_idx: 1,
},
TestOp::ClosePath {
side: Side::Client,
path_idx: 0,
error_code: 0,
},
];
let _guard = subscribe();
let (mut pair, client_config) = setup.run(prefix);
let (client_ch, server_ch) = run_random_interaction(&mut pair, interactions, client_config);
assert!(!pair.drive_bounded(1000), "connection never became idle");
assert!(allowed_error(poll_to_close(
pair.client_conn_mut(client_ch)
)));
assert!(allowed_error(poll_to_close(
pair.server_conn_mut(server_ch)
)));
}
#[test]
fn regression_peer_failed_to_respond_with_path_abandon2() {
let prefix = "regression_peer_failed_to_respond_with_path_abandon2";
let setup = PairSetup {
seed: Seed::Zeroes,
extensions: Extensions::MultipathOnly,
routing_setup: RoutingSetup::SimpleSymmetric,
};
let interactions = vec![
TestOp::OpenPath {
side: Side::Client,
status: PathStatus::Available,
addr_idx: 0,
},
TestOp::Drive { side: Side::Client },
TestOp::CloseConn {
side: Side::Server,
error_code: 0,
},
TestOp::DropInbound { side: Side::Server },
TestOp::AdvanceTime,
TestOp::Drive { side: Side::Server },
TestOp::ClosePath {
side: Side::Client,
path_idx: 0,
error_code: 0,
},
TestOp::Drive { side: Side::Server },
TestOp::DropInbound { side: Side::Client },
];
let _guard = subscribe();
let (mut pair, client_config) = setup.run(prefix);
let (client_ch, server_ch) = run_random_interaction(&mut pair, interactions, client_config);
assert!(!pair.drive_bounded(1000), "connection never became idle");
assert!(allowed_error(poll_to_close(
pair.client_conn_mut(client_ch)
)));
assert!(allowed_error(poll_to_close(
pair.server_conn_mut(server_ch)
)));
}
#[test]
fn regression_path_validation() {
let prefix = "regression_path_validation";
let setup = PairSetup {
seed: Seed::Zeroes,
extensions: Extensions::MultipathOnly,
routing_setup: RoutingSetup::Complex(RoutingTable::from_routes(
vec![("[::ffff:1.1.1.0]:44433".parse().unwrap(), 0)],
vec![
("[::ffff:2.2.2.0]:4433".parse().unwrap(), 0),
("[::ffff:2.2.2.1]:4433".parse().unwrap(), 0),
],
)),
};
let interactions = vec![
TestOp::OpenPath {
side: Side::Client,
status: PathStatus::Available,
addr_idx: 1,
},
TestOp::Drive { side: Side::Client },
TestOp::AdvanceTime,
TestOp::Drive { side: Side::Server },
TestOp::OpenPath {
side: Side::Client,
status: PathStatus::Available,
addr_idx: 1,
},
TestOp::ClosePath {
side: Side::Server,
path_idx: 0,
error_code: 0,
},
];
let _guard = subscribe();
let (mut pair, client_config) = setup.run(prefix);
let (client_ch, server_ch) = run_random_interaction(&mut pair, interactions, client_config);
assert!(!pair.drive_bounded(1000), "connection never became idle");
assert!(allowed_error(poll_to_close(
pair.client_conn_mut(client_ch)
)));
assert!(allowed_error(poll_to_close(
pair.server_conn_mut(server_ch)
)));
}
#[test]
fn regression_never_idle3() {
let prefix = "regression_never_idle3";
let setup = PairSetup {
seed: Seed::Zeroes,
extensions: Extensions::MultipathOnly,
routing_setup: RoutingSetup::SimpleSymmetric,
};
let interactions = vec![
TestOp::CloseConn {
side: Side::Server,
error_code: 0,
},
TestOp::Drive { side: Side::Server },
TestOp::DropInbound { side: Side::Client },
TestOp::OpenPath {
side: Side::Client,
status: PathStatus::Available,
addr_idx: 0,
},
TestOp::ClosePath {
side: Side::Client,
path_idx: 0,
error_code: 0,
},
TestOp::AdvanceTime,
];
let _guard = subscribe();
let (mut pair, client_config) = setup.run(prefix);
let (client_ch, server_ch) = run_random_interaction(&mut pair, interactions, client_config);
assert!(!pair.drive_bounded(1000), "connection never became idle");
assert!(allowed_error(poll_to_close(
pair.client_conn_mut(client_ch)
)));
assert!(allowed_error(poll_to_close(
pair.server_conn_mut(server_ch)
)));
}
#[test]
fn regression_frame_encoding_error() {
let prefix = "regression_frame_encoding_error";
let setup = PairSetup {
seed: Seed::Zeroes,
extensions: Extensions::MultipathOnly,
routing_setup: RoutingSetup::SimpleSymmetric,
};
let interactions = vec![
TestOp::OpenPath {
side: Side::Client,
status: PathStatus::Available,
addr_idx: 1,
},
TestOp::OpenPath {
side: Side::Client,
status: PathStatus::Available,
addr_idx: 0,
},
TestOp::ClosePath {
side: Side::Client,
path_idx: 0,
error_code: 0,
},
];
let _guard = subscribe();
let (mut pair, client_config) = setup.run(prefix);
let (client_ch, server_ch) = run_random_interaction(&mut pair, interactions, client_config);
assert!(!pair.drive_bounded(1000), "connection never became idle");
assert!(allowed_error(poll_to_close(
pair.client_conn_mut(client_ch)
)));
assert!(allowed_error(poll_to_close(
pair.server_conn_mut(server_ch)
)));
}
#[test]
fn regression_there_should_be_at_least_one_path() {
let prefix = "regression_there_should_be_at_least_one_path";
let setup = PairSetup {
seed: Seed::Zeroes,
extensions: Extensions::MultipathOnly,
routing_setup: RoutingSetup::SimpleSymmetric,
};
let interactions = vec![
TestOp::PassiveMigration {
side: Side::Client,
addr_idx: 0,
},
TestOp::CloseConn {
side: Side::Client,
error_code: 0,
},
];
let _guard = subscribe();
let (mut pair, client_config) = setup.run(prefix);
let (client_ch, server_ch) = run_random_interaction(&mut pair, interactions, client_config);
assert!(!pair.drive_bounded(1000), "connection never became idle");
assert!(allowed_error(poll_to_close(
pair.client_conn_mut(client_ch)
)));
assert!(allowed_error(poll_to_close(
pair.server_conn_mut(server_ch)
)));
}
#[test]
fn regression_conn_never_idle5() {
let prefix = "regression_conn_never_idle5";
let setup = PairSetup {
seed: Seed::Zeroes,
extensions: Extensions::MultipathOnly,
routing_setup: RoutingSetup::SimpleSymmetric,
};
let interactions = vec![
TestOp::PassiveMigration {
side: Side::Server,
addr_idx: 0,
},
TestOp::OpenPath {
side: Side::Client,
status: PathStatus::Available,
addr_idx: 0,
},
];
let _guard = subscribe();
let (mut pair, client_config) = setup.run(prefix);
let (client_ch, server_ch) = run_random_interaction(&mut pair, interactions, client_config);
assert!(!pair.drive_bounded(1000), "connection never became idle");
assert!(allowed_error(poll_to_close(
pair.client_conn_mut(client_ch)
)));
assert!(allowed_error(poll_to_close(
pair.server_conn_mut(server_ch)
)));
}
#[test]
fn regression_peer_ignored_path_abandon() {
let prefix = "regression_peer_ignored_path_abandon";
let setup = PairSetup {
seed: Seed::Zeroes,
extensions: Extensions::MultipathOnly,
routing_setup: RoutingSetup::SimpleSymmetric,
};
let interactions = vec![
TestOp::OpenPath {
side: Side::Client,
status: PathStatus::Available,
addr_idx: 0,
},
TestOp::Drive { side: Side::Client },
TestOp::PathSetStatus {
side: Side::Client,
path_idx: 0,
status: PathStatus::Backup,
},
TestOp::AdvanceTime,
TestOp::Drive { side: Side::Server },
TestOp::PassiveMigration {
side: Side::Client,
addr_idx: 0,
},
TestOp::ClosePath {
side: Side::Server,
path_idx: 1,
error_code: 0,
},
];
let _guard = subscribe();
let (mut pair, client_config) = setup.run(prefix);
let (client_ch, server_ch) = run_random_interaction(&mut pair, interactions, client_config);
assert!(!pair.drive_bounded(1000), "connection never became idle");
assert!(allowed_error(poll_to_close(
pair.client_conn_mut(client_ch)
)));
assert!(allowed_error(poll_to_close(
pair.server_conn_mut(server_ch)
)));
}
#[test]
fn regression_never_idle4() {
let prefix = "regression_never_idle4";
let setup = PairSetup {
seed: Seed::Zeroes,
extensions: Extensions::MultipathOnly,
routing_setup: RoutingSetup::Complex(RoutingTable::from_routes(
vec![
("[::ffff:1.1.1.0]:44433".parse().unwrap(), 0),
("[::ffff:1.1.1.1]:44433".parse().unwrap(), 0),
],
vec![("[::ffff:2.2.2.0]:4433".parse().unwrap(), 0)],
)),
};
let interactions = vec![
TestOp::OpenPath {
side: Side::Client,
status: PathStatus::Backup,
addr_idx: 0,
},
TestOp::PathSetStatus {
side: Side::Client,
path_idx: 0,
status: PathStatus::Backup,
},
TestOp::Drive { side: Side::Client },
TestOp::DropInbound { side: Side::Server },
TestOp::PassiveMigration {
side: Side::Client,
addr_idx: 0,
},
TestOp::AdvanceTime,
TestOp::ClosePath {
side: Side::Client,
path_idx: 0,
error_code: 0,
},
TestOp::Drive { side: Side::Client },
TestOp::PassiveMigration {
side: Side::Client,
addr_idx: 0,
},
];
let _guard = subscribe();
let (mut pair, client_config) = setup.run(prefix);
let (client_ch, server_ch) = run_random_interaction(&mut pair, interactions, client_config);
assert!(!pair.drive_bounded(1000), "connection never became idle");
assert!(allowed_error(poll_to_close(
pair.client_conn_mut(client_ch)
)));
assert!(allowed_error(poll_to_close(
pair.server_conn_mut(server_ch)
)));
}
#[test]
fn regression_infinite_loop() {
let prefix = "regression_infinite_loop";
let setup = PairSetup {
seed: Seed::Zeroes,
extensions: Extensions::MultipathOnly,
routing_setup: RoutingSetup::SimpleSymmetric,
};
let interactions = vec![
TestOp::OpenPath {
side: Side::Client,
status: PathStatus::Available,
addr_idx: 0,
},
TestOp::OpenPath {
side: Side::Client,
status: PathStatus::Available,
addr_idx: 1,
},
TestOp::PassiveMigration {
side: Side::Server,
addr_idx: 0,
},
];
let _guard = subscribe();
let (mut pair, client_config) = setup.run(prefix);
let (client_ch, server_ch) = run_random_interaction(&mut pair, interactions, client_config);
assert!(!pair.drive_bounded(1000), "connection never became idle");
assert!(allowed_error(poll_to_close(
pair.client_conn_mut(client_ch)
)));
assert!(allowed_error(poll_to_close(
pair.server_conn_mut(server_ch)
)));
}
#[test]
fn regression_qnt_revalidating_path_forever() {
let prefix = "regression_qnt_revalidating_path_forever";
let setup = PairSetup {
seed: Seed::Zeroes,
extensions: Extensions::QntAndMultipath,
routing_setup: RoutingSetup::SimpleSymmetric,
};
let interactions = vec![
TestOp::AddHpAddr {
side: Side::Server,
addr_idx: 0,
},
TestOp::Drive { side: Side::Server },
TestOp::AdvanceTime,
TestOp::Drive { side: Side::Client },
TestOp::PassiveMigration {
side: Side::Server,
addr_idx: 0,
},
TestOp::AddHpAddr {
side: Side::Client,
addr_idx: 0,
},
TestOp::InitiateHpRound { side: Side::Client },
];
let _guard = subscribe();
let (mut pair, client_config) = setup.run(prefix);
let (client_ch, server_ch) = run_random_interaction(&mut pair, interactions, client_config);
assert!(!pair.drive_bounded(1000), "connection never became idle");
assert!(allowed_error(poll_to_close(
pair.client_conn_mut(client_ch)
)));
assert!(allowed_error(poll_to_close(
pair.server_conn_mut(server_ch)
)));
}