Skip to content

Commit

Permalink
fix(netcheck): Build test ProbePlan from fake interface data (#1266)
Browse files Browse the repository at this point in the history
The tests are supposed to be purely algorithmic, but they were reliant
on the local interfaces discovered which made them fickle.  This
spells out the interface which is much more reliable.

More variations in the interface states are probably useful too, but
for now this gives us some basic coverage of probe plans.

Closes #1263
  • Loading branch information
flub authored Jul 19, 2023
1 parent 4c67385 commit f671aa5
Show file tree
Hide file tree
Showing 2 changed files with 82 additions and 90 deletions.
75 changes: 75 additions & 0 deletions iroh-net/src/net/interfaces.rs
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,47 @@ impl Interface {
.map(IpNet::V4)
.chain(self.iface.ipv6.iter().cloned().map(IpNet::V6))
}

/// Creates a fake interface for usage in tests.
///
/// Sometimes tests want to be deterministic, e.g. [`ProbePlan`] tests rely on the
/// interface state. This allows tests to be independent of the host interfaces.
///
/// It is rather possible that we'll want more variations of this in the future, feel
/// free to add parameters or different alternative constructors.
///
/// [`ProbePlan`]: crate::netcheck::reportgen::probes::ProbePlan
#[cfg(test)]
pub(crate) fn fake() -> Self {
use std::net::Ipv4Addr;

use default_net::interface::{InterfaceType, MacAddr};
use default_net::Gateway;

Self {
iface: default_net::Interface {
index: 2,
name: String::from("wifi0"),
friendly_name: None,
description: None,
if_type: InterfaceType::Ethernet,
mac_addr: Some(MacAddr::new([2, 3, 4, 5, 6, 7])),
ipv4: vec![Ipv4Net {
addr: Ipv4Addr::from([192, 168, 0, 189]),
prefix_len: 24,
netmask: Ipv4Addr::from([255, 255, 255, 0]),
}],
ipv6: vec![],
flags: 69699,
transmit_speed: None,
receive_speed: None,
gateway: Some(Gateway {
mac_addr: MacAddr::new([2, 3, 4, 5, 6, 8]),
ip_addr: IpAddr::V4(Ipv4Addr::from([192, 168, 0, 1])),
}),
},
}
}
}

/// Structure of an IP network, either IPv4 or IPv6.
Expand Down Expand Up @@ -185,6 +226,40 @@ impl State {
}
}

/// Creates a fake interface state for usage in tests.
///
/// Sometimes tests want to be deterministic, e.g. [`ProbePlan`] tests rely on the
/// interface state. This allows tests to be independent of the host interfaces.
///
/// It is rather possible that we'll want more variations of this in the future, feel
/// free to add parameters or different alternative constructors.
///
/// [`ProbePlan`]: crate::netcheck::reportgen::probes::ProbePlan
#[cfg(test)]
pub(crate) fn fake() -> Self {
let fake = Interface::fake();
let ifname = fake.iface.name.clone();
Self {
interface_ips: [(
ifname.clone(),
fake.iface
.ipv4
.iter()
.map(|net| IpNet::V4(net.clone()))
.collect(),
)]
.into_iter()
.collect(),
interface: [(ifname.clone(), fake)].into_iter().collect(),
have_v6: false,
have_v4: true,
is_expensive: false,
default_route_interface: Some(ifname),
http_proxy: None,
pac: None,
}
}

/// Is a PAC set?
pub fn has_pac(&self) -> bool {
self.pac.is_some()
Expand Down
97 changes: 7 additions & 90 deletions iroh-net/src/netcheck/reportgen/probes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -499,6 +499,7 @@ mod tests {
use pretty_assertions::assert_eq;

use crate::defaults::default_derp_map;
use crate::net::interfaces;
use crate::netcheck::RegionLatencies;

use super::*;
Expand All @@ -508,10 +509,10 @@ mod tests {
let derp_map = default_derp_map();
let derp_node_1 = Arc::new(derp_map.regions[&1].nodes[0].clone());
let derp_node_2 = Arc::new(derp_map.regions[&2].nodes[0].clone());
let if_state = crate::net::interfaces::State::new().await;
let if_state = interfaces::State::fake();
let plan = ProbePlan::initial(&derp_map, &if_state);

let mut expected_plan: ProbePlan = [
let expected_plan: ProbePlan = [
ProbeSet {
name: "region-1-stunipv4".into(),
proto: ProbeProto::StunIpv4,
Expand Down Expand Up @@ -565,7 +566,7 @@ mod tests {
},
Probe::Icmp {
delay: Duration::from_millis(500),
node: derp_node_1.clone(),
node: derp_node_1,
},
],
},
Expand Down Expand Up @@ -622,51 +623,13 @@ mod tests {
},
Probe::Icmp {
delay: Duration::from_millis(800),
node: derp_node_2.clone(),
node: derp_node_2,
},
],
},
]
.into_iter()
.collect();
if if_state.have_v6 {
expected_plan.add(ProbeSet {
name: "region-1-stunipv6".into(),
proto: ProbeProto::StunIpv6,
probes: vec![
Probe::StunIpv6 {
delay: Duration::ZERO,
node: derp_node_1.clone(),
},
Probe::StunIpv6 {
delay: Duration::from_millis(100),
node: derp_node_1.clone(),
},
Probe::StunIpv6 {
delay: Duration::from_millis(200),
node: derp_node_1.clone(),
},
],
});
expected_plan.add(ProbeSet {
name: "region-2-stunipv6".into(),
proto: ProbeProto::StunIpv6,
probes: vec![
Probe::StunIpv6 {
delay: Duration::ZERO,
node: derp_node_2.clone(),
},
Probe::StunIpv6 {
delay: Duration::from_millis(100),
node: derp_node_2.clone(),
},
Probe::StunIpv6 {
delay: Duration::from_millis(200),
node: derp_node_2.clone(),
},
],
});
}

println!("expected:");
println!("{expected_plan}");
Expand All @@ -685,7 +648,7 @@ mod tests {
let derp_map = default_derp_map();
let derp_node_1 = Arc::new(derp_map.regions[&1].nodes[0].clone());
let derp_node_2 = Arc::new(derp_map.regions[&2].nodes[0].clone());
let if_state = crate::net::interfaces::State::new().await;
let if_state = interfaces::State::fake();
let mut latencies = RegionLatencies::new();
latencies.update_region(1, Duration::from_millis(2));
latencies.update_region(2, Duration::from_millis(2));
Expand All @@ -709,7 +672,7 @@ mod tests {
captive_portal: None,
};
let plan = ProbePlan::with_last_report(&derp_map, &if_state, &last_report);
let mut expected_plan: ProbePlan = [
let expected_plan: ProbePlan = [
ProbeSet {
name: "region-1-stunipv4".into(),
proto: ProbeProto::StunIpv4,
Expand Down Expand Up @@ -827,52 +790,6 @@ mod tests {
]
.into_iter()
.collect();
if if_state.have_v6 {
expected_plan.add(ProbeSet {
name: "region-1-stunipv6".into(),
proto: ProbeProto::StunIpv6,
probes: vec![
Probe::StunIpv6 {
delay: Duration::ZERO,
node: derp_node_1.clone(),
},
Probe::StunIpv6 {
delay: Duration::from_micros(52_400),
node: derp_node_1.clone(),
},
Probe::StunIpv6 {
delay: Duration::from_micros(104_800),
node: derp_node_1.clone(),
},
Probe::StunIpv6 {
delay: Duration::from_micros(157_200),
node: derp_node_1.clone(),
},
],
});
expected_plan.add(ProbeSet {
name: "region-2-stunipv6".into(),
proto: ProbeProto::StunIpv6,
probes: vec![
Probe::StunIpv6 {
delay: Duration::ZERO,
node: derp_node_2.clone(),
},
Probe::StunIpv6 {
delay: Duration::from_micros(52_400),
node: derp_node_2.clone(),
},
Probe::StunIpv6 {
delay: Duration::from_micros(104_800),
node: derp_node_2.clone(),
},
Probe::StunIpv6 {
delay: Duration::from_micros(157_200),
node: derp_node_2.clone(),
},
],
})
}

println!("{} round", i);
println!("expected:");
Expand Down

0 comments on commit f671aa5

Please sign in to comment.