Skip to content

Commit

Permalink
test(iroh-relay, netcheck): move tests to use local relays (#2935)
Browse files Browse the repository at this point in the history
## Description

Removes `netcheck`'s dependency on staging relays, using locally served
ones instead. This is necessary to move netcheck out without needing to
find an appropriate place for the staging values to prevent circular
dependecies

## Breaking Changes

- `RelayMap` now can be created with an iterator of `Arc`s directly.

## Notes & open questions

- a test was removed since it doesn't test properties of netcheck, it
just connects to the staging relay
- `iroh-relay/src/server/testing.rs` was added by mistake in the split
pr, so the deletions are not really picked by rust and all new code
should be considered.. well, new.

## Change checklist

- [x] Self-review.
- [ ] ~~Documentation updates following the [style
guide](https://rust-lang.github.io/rfcs/1574-more-api-documentation-conventions.html#appendix-a-full-conventions-text),
if relevant.~~
- [ ] ~~Tests if relevant.~~
- [ ] ~~All breaking changes documented.~~
  • Loading branch information
divagant-martian authored Nov 18, 2024
1 parent fbcb056 commit 8edaee9
Show file tree
Hide file tree
Showing 7 changed files with 178 additions and 187 deletions.
1 change: 1 addition & 0 deletions iroh-net/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,7 @@ iroh-net = { path = "." }
serde_json = "1.0.107"
testresult = "0.4.0"
mainline = "2.0.1"
iroh-relay = { version = "0.28", path = "../iroh-relay", features = ["test-utils", "server"] }

[[bench]]
name = "key"
Expand Down
99 changes: 41 additions & 58 deletions iroh-net/src/netcheck.rs
Original file line number Diff line number Diff line change
Expand Up @@ -769,6 +769,46 @@ pub(crate) fn os_has_ipv6() -> bool {
UdpSocket::bind_local_v6(0).is_ok()
}

#[cfg(test)]
mod test_utils {
//! Creates a relay server against which to perform tests
use std::sync::Arc;

use iroh_relay::server;

use crate::RelayNode;

pub(crate) async fn relay() -> (server::Server, Arc<RelayNode>) {
let server = server::Server::spawn(server::testing::server_config())
.await
.expect("should serve relay");
let node_desc = RelayNode {
url: server.https_url().expect("should work as relay"),
stun_only: false, // the checks above and below guarantee both stun and relay
stun_port: server.stun_addr().expect("server should serve stun").port(),
};

(server, Arc::new(node_desc))
}

/// Create a [`crate::RelayMap`] of the given size.
///
/// This function uses [`relay`]. Note that the returned map uses internal order that will
/// often _not_ match the order of the servers.
pub(crate) async fn relay_map(relays: usize) -> (Vec<server::Server>, crate::RelayMap) {
let mut servers = Vec::with_capacity(relays);
let mut nodes = Vec::with_capacity(relays);
for _ in 0..relays {
let (relay_server, node) = relay().await;
servers.push(relay_server);
nodes.push(node);
}
let map = crate::RelayMap::from_nodes(nodes).expect("unuque urls");
(servers, map)
}
}

#[cfg(test)]
mod tests {
use std::net::Ipv4Addr;
Expand All @@ -778,11 +818,7 @@ mod tests {
use tracing::info;

use super::*;
use crate::{
defaults::{staging::EU_RELAY_HOSTNAME, DEFAULT_STUN_PORT},
ping::Pinger,
RelayNode,
};
use crate::ping::Pinger;

mod stun_utils {
//! Utils for testing that expose a simple stun server.
Expand All @@ -799,8 +835,6 @@ mod tests {
use super::*;
use crate::{RelayMap, RelayNode, RelayUrl};

// TODO: make all this private

/// A drop guard to clean up test infrastructure.
///
/// After dropping the test infrastructure will asynchronously shutdown and release its
Expand Down Expand Up @@ -956,57 +990,6 @@ mod tests {
Ok(())
}

#[tokio::test]
async fn test_iroh_computer_stun() -> Result<()> {
let _guard = iroh_test::logging::setup();

let resolver = crate::dns::default_resolver().clone();
let mut client = Client::new(None, resolver).context("failed to create netcheck client")?;
let url: RelayUrl = format!("https://{}", EU_RELAY_HOSTNAME).parse().unwrap();

let dm = RelayMap::from_nodes([RelayNode {
url: url.clone(),
stun_only: true,
stun_port: DEFAULT_STUN_PORT,
}])
.expect("hardcoded");

for i in 0..10 {
println!("starting report {}", i + 1);
let now = Instant::now();

let r = client
.get_report(dm.clone(), None, None)
.await
.context("failed to get netcheck report")?;

if r.udp {
assert_eq!(
r.relay_latency.len(),
1,
"expected 1 key in RelayLatency; got {}",
r.relay_latency.len()
);
assert!(
r.relay_latency.iter().next().is_some(),
"expected key 1 in RelayLatency; got {:?}",
r.relay_latency
);
assert!(
r.global_v4.is_some() || r.global_v6.is_some(),
"expected at least one of global_v4 or global_v6"
);
assert!(r.preferred_relay.is_some());
} else {
eprintln!("missing UDP, probe not returned by network");
}

println!("report {} done in {:?}", i + 1, now.elapsed());
}

Ok(())
}

#[tokio::test]
async fn test_udp_blocked() -> Result<()> {
let _guard = iroh_test::logging::setup();
Expand Down
90 changes: 40 additions & 50 deletions iroh-net/src/netcheck/reportgen.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1177,101 +1177,99 @@ mod tests {

use testresult::TestResult;

use super::*;
use crate::{
defaults::staging::{default_eu_relay_node, default_na_relay_node},
test_utils,
};
use super::{super::test_utils, *};

#[test]
fn test_update_report_stun_working() {
let eu_relayer = Arc::new(default_eu_relay_node());
let na_relayer = Arc::new(default_na_relay_node());
#[tokio::test]
async fn test_update_report_stun_working() {
let _logging = iroh_test::logging::setup();
let (_server_a, relay_a) = test_utils::relay().await;
let (_server_b, relay_b) = test_utils::relay().await;

let mut report = Report::default();

// A STUN IPv4 probe from the EU relay server.
let probe_report_eu = ProbeReport {
// A STUN IPv4 probe from the the first relay server.
let probe_report_a = ProbeReport {
ipv4_can_send: true,
ipv6_can_send: false,
icmpv4: None,
icmpv6: None,
latency: Some(Duration::from_millis(5)),
probe: Probe::StunIpv4 {
delay: Duration::ZERO,
node: eu_relayer.clone(),
node: relay_a.clone(),
},
addr: Some((Ipv4Addr::new(203, 0, 113, 1), 1234).into()),
};
update_report(&mut report, probe_report_eu.clone());
update_report(&mut report, probe_report_a.clone());

assert!(report.udp);
assert_eq!(
report.relay_latency.get(&eu_relayer.url).unwrap(),
report.relay_latency.get(&relay_a.url).unwrap(),
Duration::from_millis(5)
);
assert_eq!(
report.relay_v4_latency.get(&eu_relayer.url).unwrap(),
report.relay_v4_latency.get(&relay_a.url).unwrap(),
Duration::from_millis(5)
);
assert!(report.ipv4_can_send);
assert!(!report.ipv6_can_send);

// A second STUN IPv4 probe, same external IP detected but slower.
let probe_report_na = ProbeReport {
let probe_report_b = ProbeReport {
latency: Some(Duration::from_millis(8)),
probe: Probe::StunIpv4 {
delay: Duration::ZERO,
node: na_relayer.clone(),
node: relay_b.clone(),
},
..probe_report_eu
..probe_report_a
};
update_report(&mut report, probe_report_na);
update_report(&mut report, probe_report_b);

assert!(report.udp);
assert_eq!(
report.relay_latency.get(&eu_relayer.url).unwrap(),
report.relay_latency.get(&relay_a.url).unwrap(),
Duration::from_millis(5)
);
assert_eq!(
report.relay_v4_latency.get(&eu_relayer.url).unwrap(),
report.relay_v4_latency.get(&relay_a.url).unwrap(),
Duration::from_millis(5)
);
assert!(report.ipv4_can_send);
assert!(!report.ipv6_can_send);

// A STUN IPv6 probe, this one is faster.
let probe_report_eu_ipv6 = ProbeReport {
let probe_report_a_ipv6 = ProbeReport {
ipv4_can_send: false,
ipv6_can_send: true,
icmpv4: None,
icmpv6: None,
latency: Some(Duration::from_millis(4)),
probe: Probe::StunIpv6 {
delay: Duration::ZERO,
node: eu_relayer.clone(),
node: relay_a.clone(),
},
addr: Some((Ipv6Addr::new(2001, 0xdb8, 0, 0, 0, 0, 0, 1), 1234).into()),
};
update_report(&mut report, probe_report_eu_ipv6);
update_report(&mut report, probe_report_a_ipv6);

assert!(report.udp);
assert_eq!(
report.relay_latency.get(&eu_relayer.url).unwrap(),
report.relay_latency.get(&relay_a.url).unwrap(),
Duration::from_millis(4)
);
assert_eq!(
report.relay_v6_latency.get(&eu_relayer.url).unwrap(),
report.relay_v6_latency.get(&relay_a.url).unwrap(),
Duration::from_millis(4)
);
assert!(report.ipv4_can_send);
assert!(report.ipv6_can_send);
}

#[test]
fn test_update_report_icmp() {
let eu_relayer = Arc::new(default_eu_relay_node());
let na_relayer = Arc::new(default_na_relay_node());
#[tokio::test]
async fn test_update_report_icmp() {
let _logging = iroh_test::logging::setup();
let (_server_a, relay_a) = test_utils::relay().await;
let (_server_b, relay_b) = test_utils::relay().await;

let mut report = Report::default();

Expand All @@ -1284,7 +1282,7 @@ mod tests {
latency: Some(Duration::from_millis(5)),
probe: Probe::IcmpV4 {
delay: Duration::ZERO,
node: eu_relayer.clone(),
node: relay_a.clone(),
},
addr: Some((Ipv4Addr::new(203, 0, 113, 1), 1234).into()),
};
Expand All @@ -1303,7 +1301,7 @@ mod tests {
latency: None,
probe: Probe::IcmpV4 {
delay: Duration::ZERO,
node: na_relayer.clone(),
node: relay_b.clone(),
},
addr: None,
};
Expand All @@ -1320,7 +1318,7 @@ mod tests {
latency: Some(Duration::from_millis(5)),
probe: Probe::StunIpv4 {
delay: Duration::ZERO,
node: eu_relayer.clone(),
node: relay_a.clone(),
},
addr: Some((Ipv4Addr::new(203, 0, 113, 1), 1234).into()),
};
Expand Down Expand Up @@ -1378,18 +1376,14 @@ mod tests {
//
// TODO: Not sure what about IPv6 pings using sysctl.
#[tokio::test]
async fn test_icmpk_probe_eu_relayer() {
async fn test_icmpk_probe() {
let _logging_guard = iroh_test::logging::setup();
let pinger = Pinger::new();
let relay = default_eu_relay_node();
let resolver = crate::dns::default_resolver();
let addr = get_relay_addr(resolver, &relay, ProbeProto::IcmpV4)
.await
.map_err(|err| format!("{err:#}"))
.unwrap();
let (server, node) = test_utils::relay().await;
let addr = server.stun_addr().expect("test relay serves stun");
let probe = Probe::IcmpV4 {
delay: Duration::from_secs(0),
node: Arc::new(relay),
node,
};

// A single ICMP packet might get lost. Try several and take the first.
Expand Down Expand Up @@ -1434,20 +1428,16 @@ mod tests {
#[tokio::test]
async fn test_measure_https_latency() -> TestResult {
let _logging_guard = iroh_test::logging::setup();
let (_relay_map, relay_url, server) = test_utils::run_relay_server().await?;
let (server, relay) = test_utils::relay().await;
let dns_resolver = crate::dns::resolver();
warn!(?relay_url, "RELAY_URL");
let node = RelayNode {
stun_only: false,
stun_port: 0,
url: relay_url.clone(),
};
tracing::info!(relay_url = ?relay.url , "RELAY_URL");
let (latency, ip) =
measure_https_latency(dns_resolver, &node, server.certificates()).await?;
measure_https_latency(dns_resolver, &relay, server.certificates()).await?;

assert!(latency > Duration::ZERO);

let relay_url_ip = relay_url
let relay_url_ip = relay
.url
.host_str()
.context("host")?
.parse::<std::net::IpAddr>()?;
Expand Down
Loading

0 comments on commit 8edaee9

Please sign in to comment.