Skip to content

Commit 17c4e2e

Browse files
committed
cleanup test code
1 parent 1f66a81 commit 17c4e2e

4 files changed

Lines changed: 77 additions & 147 deletions

File tree

iroh-relay/src/client/tls.rs

Lines changed: 18 additions & 92 deletions
Original file line numberDiff line numberDiff line change
@@ -373,54 +373,19 @@ fn url_port(url: &Url) -> Option<u16> {
373373
mod tests {
374374
use std::net::{Ipv4Addr, Ipv6Addr};
375375

376-
use iroh_dns::dns::{BoxIter, DnsError, DnsResolver, Resolver, TxtRecordData};
377-
use n0_future::boxed::BoxFuture;
378376
use tokio::net::TcpListener;
379377

380-
use super::*;
381-
382-
/// Resolver that hands out fixed IPv4 and IPv6 addresses for every host.
383-
#[derive(Debug, Clone)]
384-
struct StaticResolver {
385-
v4: Vec<Ipv4Addr>,
386-
v6: Vec<Ipv6Addr>,
387-
}
388-
389-
impl Resolver for StaticResolver {
390-
fn lookup_ipv4(&self, _host: String) -> BoxFuture<Result<BoxIter<Ipv4Addr>, DnsError>> {
391-
let addrs: BoxIter<_> = Box::new(self.v4.clone().into_iter());
392-
Box::pin(std::future::ready(Ok(addrs)))
393-
}
394-
395-
fn lookup_ipv6(&self, _host: String) -> BoxFuture<Result<BoxIter<Ipv6Addr>, DnsError>> {
396-
let addrs: BoxIter<_> = Box::new(self.v6.clone().into_iter());
397-
Box::pin(std::future::ready(Ok(addrs)))
398-
}
378+
use crate::test_utils::StaticResolver;
399379

400-
fn lookup_txt(&self, _host: String) -> BoxFuture<Result<BoxIter<TxtRecordData>, DnsError>> {
401-
let records: BoxIter<_> = Box::new(std::iter::empty());
402-
Box::pin(std::future::ready(Ok(records)))
403-
}
404-
405-
fn clear_cache(&self) {}
406-
407-
fn reset(&self) -> Box<dyn Resolver> {
408-
Box::new(self.clone())
409-
}
410-
}
411-
412-
fn resolver(v4: Vec<Ipv4Addr>, v6: Vec<Ipv6Addr>) -> DnsResolver {
413-
DnsResolver::custom(StaticResolver { v4, v6 })
414-
}
380+
use super::*;
415381

416382
fn relay_url(port: u16) -> Url {
417383
format!("http://relay.test:{port}")
418384
.parse()
419385
.expect("valid url")
420386
}
421387

422-
/// An unreachable IPv4 address (RFC 5737 TEST-NET-1): a connection attempt to
423-
/// it never succeeds, modelling a stale or dead record.
388+
/// An unreachable IPv4 address (RFC 5737 TEST-NET-1).
424389
fn dead_v4(n: u8) -> Ipv4Addr {
425390
Ipv4Addr::new(192, 0, 2, n)
426391
}
@@ -430,85 +395,46 @@ mod tests {
430395
Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, n)
431396
}
432397

433-
/// Runs the dialer against `relay.test` on `port`. An attempt to an
434-
/// unreachable address is capped by [`DIAL_ENDPOINT_TIMEOUT`] internally, so
435-
/// the dialer always makes progress; the outer timeout only guards against a
436-
/// true hang.
437-
async fn dial(
438-
resolver: &DnsResolver,
439-
port: u16,
440-
prefer_ipv6: bool,
441-
) -> Result<TcpStream, DialError> {
442-
time::timeout(
443-
time::Duration::from_secs(10),
444-
dial_happy_eyeballs(resolver, &relay_url(port), prefer_ipv6),
445-
)
446-
.await
447-
.expect("dialer finishes in time")
448-
}
449-
450-
#[tokio::test]
451-
async fn connects_to_the_resolved_address() {
452-
let listener = TcpListener::bind((Ipv4Addr::LOCALHOST, 0)).await.unwrap();
453-
let port = listener.local_addr().unwrap().port();
454-
455-
let stream = dial(&resolver(vec![Ipv4Addr::LOCALHOST], vec![]), port, false)
456-
.await
457-
.expect("connects to the listener");
458-
assert_eq!(
459-
stream.peer_addr().unwrap(),
460-
(Ipv4Addr::LOCALHOST, port).into()
461-
);
462-
}
463-
398+
/// Tests that all addresses are tried until one succeeds.
464399
#[tokio::test]
465400
async fn tries_addresses_until_one_connects() {
466401
let listener = TcpListener::bind((Ipv4Addr::LOCALHOST, 0)).await.unwrap();
467402
let port = listener.local_addr().unwrap().port();
468403

469-
// Vary the number of unreachable addresses preceding the reachable one:
470-
// the dialer should skip the dead ones and still connect.
471-
for dead in [0u8, 1, 3] {
472-
let v4 = (1..=dead)
473-
.map(dead_v4)
474-
.chain([Ipv4Addr::LOCALHOST])
475-
.collect();
476-
let stream = dial(&resolver(v4, vec![]), port, false)
477-
.await
478-
.unwrap_or_else(|err| panic!("connects with {dead} dead addresses: {err:#}"));
479-
assert_eq!(stream.peer_addr().unwrap().ip(), Ipv4Addr::LOCALHOST);
480-
}
404+
let addrs = (1..5).map(dead_v4).chain([Ipv4Addr::LOCALHOST]).collect();
405+
let resolver = StaticResolver::new(addrs, vec![]);
406+
let stream = dial_happy_eyeballs(&resolver, &relay_url(port), false)
407+
.await
408+
.expect("should skip the invalid addrs and still connect");
409+
assert_eq!(stream.peer_addr().unwrap().ip(), Ipv4Addr::LOCALHOST);
481410
}
482411

412+
/// Tests if the preferred family is unreachable the non-preferred family is used.
483413
#[tokio::test]
484414
async fn falls_back_from_unreachable_preferred_family() {
485-
// IPv6 is preferred but every IPv6 address is unreachable; the dialer must
486-
// interleave across families and fall back to the reachable IPv4 address.
487415
let listener = TcpListener::bind((Ipv4Addr::LOCALHOST, 0)).await.unwrap();
488416
let port = listener.local_addr().unwrap().port();
489-
let resolver = resolver(vec![Ipv4Addr::LOCALHOST], vec![dead_v6(1), dead_v6(2)]);
417+
let resolver = StaticResolver::new(vec![Ipv4Addr::LOCALHOST], vec![dead_v6(1), dead_v6(2)]);
490418

491-
let stream = dial(&resolver, port, true)
419+
let stream = dial_happy_eyeballs(&resolver, &relay_url(port), true)
492420
.await
493421
.expect("falls back to IPv4");
494422
assert!(stream.peer_addr().unwrap().is_ipv4());
495423
}
496424

497425
#[tokio::test]
498426
async fn errors_when_all_addresses_unreachable() {
499-
let resolver = resolver(vec![dead_v4(1), dead_v4(2)], vec![dead_v6(1)]);
500-
let err = dial(&resolver, 8080, true)
427+
let resolver = StaticResolver::new(vec![dead_v4(1), dead_v4(2)], vec![dead_v6(1)]);
428+
let err = dial_happy_eyeballs(&resolver, &relay_url(80), true)
501429
.await
502430
.expect_err("nothing reachable");
503-
assert!(matches!(
504-
err,
505-
DialError::Io { .. } | DialError::Timeout { .. }
506-
));
431+
assert!(matches!(err, DialError::Io { .. }));
507432
}
508433

509434
#[tokio::test]
510435
async fn errors_when_nothing_resolves() {
511-
let err = dial_happy_eyeballs(&resolver(vec![], vec![]), &relay_url(80), false)
436+
let resolver = StaticResolver::new(vec![], vec![]);
437+
let err = dial_happy_eyeballs(&resolver, &relay_url(80), false)
512438
.await
513439
.expect_err("no addresses to dial");
514440
assert!(matches!(err, DialError::Dns { .. }));

iroh-relay/src/lib.rs

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -33,21 +33,21 @@
3333
pub mod client;
3434
pub mod defaults;
3535
pub mod http;
36+
mod key_cache;
37+
mod ping_tracker;
3638
pub mod protos;
3739
pub mod quic;
40+
mod relay_map;
3841
#[cfg(feature = "server")]
3942
pub mod server;
43+
#[cfg(test)]
44+
pub(crate) mod test_utils;
4045
pub mod tls;
4146

42-
mod ping_tracker;
43-
44-
mod key_cache;
45-
mod relay_map;
46-
pub use key_cache::KeyCache;
47-
pub use protos::relay::MAX_PACKET_SIZE;
48-
4947
pub use crate::{
48+
key_cache::KeyCache,
5049
ping_tracker::PingTracker,
50+
protos::relay::MAX_PACKET_SIZE,
5151
relay_map::{RelayConfig, RelayMap, RelayQuicConfig},
5252
};
5353

iroh-relay/src/server.rs

Lines changed: 12 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -1156,17 +1156,13 @@ impl hyper::service::Service<Request<Incoming>> for CaptivePortalService {
11561156

11571157
#[cfg(test)]
11581158
mod tests {
1159-
use std::{
1160-
net::{Ipv4Addr, Ipv6Addr},
1161-
sync::Arc,
1162-
time::Duration,
1163-
};
1159+
use std::{net::Ipv4Addr, sync::Arc, time::Duration};
11641160

11651161
use http::StatusCode;
11661162
use iroh_base::{EndpointId, RelayUrl, SecretKey};
1167-
use iroh_dns::dns::{BoxIter, DnsError, DnsResolver, Resolver, TxtRecordData};
1163+
use iroh_dns::dns::DnsResolver;
11681164
use n0_error::{Result, StackResultExt, StdResultExt};
1169-
use n0_future::{SinkExt, StreamExt, boxed::BoxFuture};
1165+
use n0_future::{SinkExt, StreamExt};
11701166
use n0_tracing_test::traced_test;
11711167
use rand::{RngExt, SeedableRng};
11721168
use tracing::{info, instrument};
@@ -1182,6 +1178,7 @@ mod tests {
11821178
handshake,
11831179
relay::{ClientToRelayMsg, Datagrams, RelayToClientMsg},
11841180
},
1181+
test_utils::StaticResolver,
11851182
tls::{self, CaRootsConfig, default_provider},
11861183
};
11871184

@@ -1575,38 +1572,8 @@ mod tests {
15751572
Ok(())
15761573
}
15771574

1578-
/// A resolver that hands out fixed IPv4 and IPv6 addresses for every host.
1579-
#[derive(Debug, Clone)]
1580-
struct StaticResolver {
1581-
v4: Vec<Ipv4Addr>,
1582-
v6: Vec<Ipv6Addr>,
1583-
}
1584-
1585-
impl Resolver for StaticResolver {
1586-
fn lookup_ipv4(&self, _host: String) -> BoxFuture<Result<BoxIter<Ipv4Addr>, DnsError>> {
1587-
let addrs: BoxIter<_> = Box::new(self.v4.clone().into_iter());
1588-
Box::pin(std::future::ready(Ok(addrs)))
1589-
}
1590-
1591-
fn lookup_ipv6(&self, _host: String) -> BoxFuture<Result<BoxIter<Ipv6Addr>, DnsError>> {
1592-
let addrs: BoxIter<_> = Box::new(self.v6.clone().into_iter());
1593-
Box::pin(std::future::ready(Ok(addrs)))
1594-
}
1595-
1596-
fn lookup_txt(&self, _host: String) -> BoxFuture<Result<BoxIter<TxtRecordData>, DnsError>> {
1597-
let records: BoxIter<_> = Box::new(std::iter::empty());
1598-
Box::pin(std::future::ready(Ok(records)))
1599-
}
1600-
1601-
fn clear_cache(&self) {}
1602-
1603-
fn reset(&self) -> Box<dyn Resolver> {
1604-
Box::new(self.clone())
1605-
}
1606-
}
1607-
1608-
/// A relay client that prefers IPv6 falls back to IPv4 when the advertised IPv6
1609-
/// address is unreachable.
1575+
/// Regression test: A relay client that prefers IPv6 falls back to IPv4
1576+
/// when the advertised IPv6 address is unreachable.
16101577
#[tokio::test]
16111578
#[traced_test]
16121579
async fn test_relay_client_falls_back_to_ipv4() -> Result {
@@ -1618,21 +1585,18 @@ mod tests {
16181585
let server = Server::spawn(config).await?;
16191586
let addr = server.http_addr().expect("http relay address");
16201587

1621-
// `relay.test` resolves to the relay's real IPv4 address alongside an
1622-
// unreachable IPv6 address from the RFC 3849 documentation prefix, standing
1623-
// in for the stale AAAA record from the issue.
1624-
let resolver = DnsResolver::custom(StaticResolver {
1625-
v4: vec![Ipv4Addr::LOCALHOST],
1626-
v6: vec!["2001:db8::dead".parse().expect("valid IPv6")],
1627-
});
1588+
// Resolves to both the real IPv4 address and an unreachable IPv6 address.
1589+
let resolver = StaticResolver::new(
1590+
vec![Ipv4Addr::LOCALHOST],
1591+
vec!["2001:db8::dead".parse().expect("valid IPv6")],
1592+
);
16281593
let url: Url = format!("http://relay.test:{}", addr.port())
16291594
.parse()
16301595
.expect("valid relay url");
16311596

1632-
// Force the IPv6 preference, as a client with working IPv6 connectivity
1633-
// would have after a net report.
16341597
let client = ClientBuilder::new(url, SecretKey::generate(), resolver)
16351598
.tls_client_config(tls::make_dangerous_client_config())
1599+
// Force IPv6 preference
16361600
.address_family_selector(|| true);
16371601

16381602
tokio::time::timeout(Duration::from_secs(10), client.connect())

iroh-relay/src/test_utils.rs

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
use std::net::{Ipv4Addr, Ipv6Addr};
2+
3+
use iroh_dns::dns::{BoxIter, DnsError, DnsResolver, Resolver, TxtRecordData};
4+
use n0_future::boxed::BoxFuture;
5+
6+
/// Resolver that hands out fixed IPv4 and IPv6 addresses for every host.
7+
#[derive(Debug, Clone)]
8+
pub(crate) struct StaticResolver {
9+
v4: Vec<Ipv4Addr>,
10+
v6: Vec<Ipv6Addr>,
11+
}
12+
13+
impl Resolver for StaticResolver {
14+
fn lookup_ipv4(&self, _host: String) -> BoxFuture<Result<BoxIter<Ipv4Addr>, DnsError>> {
15+
let addrs: BoxIter<_> = Box::new(self.v4.clone().into_iter());
16+
Box::pin(std::future::ready(Ok(addrs)))
17+
}
18+
19+
fn lookup_ipv6(&self, _host: String) -> BoxFuture<Result<BoxIter<Ipv6Addr>, DnsError>> {
20+
let addrs: BoxIter<_> = Box::new(self.v6.clone().into_iter());
21+
Box::pin(std::future::ready(Ok(addrs)))
22+
}
23+
24+
fn lookup_txt(&self, _host: String) -> BoxFuture<Result<BoxIter<TxtRecordData>, DnsError>> {
25+
let records: BoxIter<_> = Box::new(std::iter::empty());
26+
Box::pin(std::future::ready(Ok(records)))
27+
}
28+
29+
fn clear_cache(&self) {}
30+
31+
fn reset(&self) -> Box<dyn Resolver> {
32+
Box::new(self.clone())
33+
}
34+
}
35+
36+
impl StaticResolver {
37+
pub(crate) fn new(v4: Vec<Ipv4Addr>, v6: Vec<Ipv6Addr>) -> DnsResolver {
38+
DnsResolver::custom(StaticResolver { v4, v6 })
39+
}
40+
}

0 commit comments

Comments
 (0)