Source code
Revision control
Copy as Markdown
Other Tools
/// > 6. Establishing Connections
///
mod common;
use common::*;
use std::net::SocketAddr;
use happy_eyeballs::{
CONNECTION_ATTEMPT_DELAY, ConnectionAttemptHttpVersions, DnsResult, Endpoint, Id, Input, Output,
};
#[test]
fn ipv6_blackhole() {
let (mut now, mut he) = setup();
he.expect(
vec![
(None, Some(out_send_dns_https(Id::from(0)))),
(None, Some(out_send_dns_aaaa(Id::from(1)))),
(None, Some(out_send_dns_a(Id::from(2)))),
(
Some(in_dns_https_positive(Id::from(0))),
Some(out_resolution_delay()),
),
(
Some(in_dns_a_positive(Id::from(2))),
Some(out_resolution_delay()),
),
(
Some(in_dns_aaaa_positive(Id::from(1))),
Some(out_attempt_v6_h3(Id::from(3))),
),
],
now,
);
for _ in 0..42 {
now += CONNECTION_ATTEMPT_DELAY;
let connection_attempt = he.process_output(now).unwrap().attempt().unwrap();
if connection_attempt.address.is_ipv4() {
return;
}
}
panic!("Did not fall back to IPv4.");
}
#[test]
fn connection_attempt_delay() {
let (mut now, mut he) = setup();
he.expect(
vec![
(None, Some(out_send_dns_https(Id::from(0)))),
(None, Some(out_send_dns_aaaa(Id::from(1)))),
(None, Some(out_send_dns_a(Id::from(2)))),
(
Some(in_dns_https_positive_no_alpn(Id::from(0))),
Some(out_resolution_delay()),
),
(
Some(in_dns_aaaa_positive(Id::from(1))),
Some(out_attempt_v6_h1_h2(Id::from(3))),
),
(
Some(in_dns_a_positive(Id::from(2))),
Some(out_connection_attempt_delay()),
),
],
now,
);
now += CONNECTION_ATTEMPT_DELAY;
he.expect(vec![(None, Some(out_attempt_v4_h1_h2(Id::from(4))))], now);
}
#[test]
fn never_try_same_attempt_twice() {
let (mut now, mut he) = setup();
he.expect(
vec![
(None, Some(out_send_dns_https(Id::from(0)))),
(None, Some(out_send_dns_aaaa(Id::from(1)))),
(None, Some(out_send_dns_a(Id::from(2)))),
(
Some(in_dns_https_negative(Id::from(0))),
Some(out_resolution_delay()),
),
(
Some(in_dns_a_negative(Id::from(2))),
Some(out_resolution_delay()),
),
(
Some(in_dns_aaaa_positive(Id::from(1))),
Some(out_attempt_v6_h1_h2(Id::from(3))),
),
],
now,
);
now += CONNECTION_ATTEMPT_DELAY;
he.expect(vec![(None, None)], now);
}
#[test]
fn successful_connection_cancels_others() {
let (mut now, mut he) = setup();
he.expect(
vec![
(None, Some(out_send_dns_https(Id::from(0)))),
(None, Some(out_send_dns_aaaa(Id::from(1)))),
(None, Some(out_send_dns_a(Id::from(2)))),
(
Some(in_dns_https_positive_no_alpn(Id::from(0))),
Some(out_resolution_delay()),
),
(
Some(Input::DnsResult {
id: Id::from(1),
result: DnsResult::Aaaa(Ok(vec![V6_ADDR, V6_ADDR_2])),
}),
Some(out_attempt_v6_h1_h2(Id::from(3))),
),
(
Some(in_dns_a_positive(Id::from(2))),
Some(out_connection_attempt_delay()),
),
],
now,
);
now += CONNECTION_ATTEMPT_DELAY;
he.expect(
vec![(
None,
Some(Output::AttemptConnection {
id: Id::from(4),
endpoint: Endpoint {
address: SocketAddr::new(V6_ADDR_2.into(), PORT),
protocol: ConnectionAttemptHttpVersions::H2OrH1,
ech_config: None,
},
}),
)],
now,
);
now += CONNECTION_ATTEMPT_DELAY;
he.expect(vec![(None, Some(out_attempt_v4_h1_h2(Id::from(5))))], now);
he.expect(
vec![
(
Some(in_connection_result_positive(Id::from(3))),
Some(Output::CancelConnection { id: Id::from(4) }),
),
(None, Some(Output::CancelConnection { id: Id::from(5) })),
(None, Some(Output::Succeeded)),
],
now,
);
}
#[test]
fn failed_connection_tries_next_immediately() {
let (now, mut he) = setup();
he.expect(
vec![
(None, Some(out_send_dns_https(Id::from(0)))),
(None, Some(out_send_dns_aaaa(Id::from(1)))),
(None, Some(out_send_dns_a(Id::from(2)))),
(
Some(in_dns_https_positive_no_alpn(Id::from(0))),
Some(out_resolution_delay()),
),
(
Some(in_dns_aaaa_positive(Id::from(1))),
Some(out_attempt_v6_h1_h2(Id::from(3))),
),
(
Some(in_dns_a_positive(Id::from(2))),
Some(out_connection_attempt_delay()),
),
],
now,
);
he.expect(
vec![(
Some(in_connection_result_negative(Id::from(3))),
Some(out_attempt_v4_h1_h2(Id::from(4))),
)],
now,
);
}
#[test]
fn successful_connection_emits_succeeded() {
let (now, mut he) = setup();
he.expect(
vec![
(None, Some(out_send_dns_https(Id::from(0)))),
(None, Some(out_send_dns_aaaa(Id::from(1)))),
(None, Some(out_send_dns_a(Id::from(2)))),
(
Some(in_dns_https_positive_no_alpn(Id::from(0))),
Some(out_resolution_delay()),
),
(
Some(in_dns_aaaa_positive(Id::from(1))),
Some(out_attempt_v6_h1_h2(Id::from(3))),
),
(
Some(in_connection_result_positive(Id::from(3))),
Some(Output::Succeeded),
),
],
now,
);
}
#[test]
fn succeeded_keeps_emitting_succeeded() {
let (now, mut he) = setup();
he.expect(
vec![
(None, Some(out_send_dns_https(Id::from(0)))),
(None, Some(out_send_dns_aaaa(Id::from(1)))),
(None, Some(out_send_dns_a(Id::from(2)))),
(
Some(in_dns_https_positive_no_alpn(Id::from(0))),
Some(out_resolution_delay()),
),
(
Some(in_dns_aaaa_positive(Id::from(1))),
Some(out_attempt_v6_h1_h2(Id::from(3))),
),
(
Some(in_connection_result_positive(Id::from(3))),
Some(Output::Succeeded),
),
// After succeeded, continue to emit Succeeded
(None, Some(Output::Succeeded)),
(None, Some(Output::Succeeded)),
],
now,
);
}
#[test]
fn cancelled_connection_result_ignored() {
let (mut now, mut he) = setup();
he.expect(
vec![
(None, Some(out_send_dns_https(Id::from(0)))),
(None, Some(out_send_dns_aaaa(Id::from(1)))),
(None, Some(out_send_dns_a(Id::from(2)))),
(
Some(in_dns_https_positive_no_alpn(Id::from(0))),
Some(out_resolution_delay()),
),
(
Some(in_dns_aaaa_positive(Id::from(1))),
Some(out_attempt_v6_h1_h2(Id::from(3))),
),
(
Some(in_dns_a_positive(Id::from(2))),
Some(out_connection_attempt_delay()),
),
],
now,
);
now += CONNECTION_ATTEMPT_DELAY;
// Start second connection attempt.
he.expect(vec![(None, Some(out_attempt_v4_h1_h2(Id::from(4))))], now);
// First connection succeeds, triggering cancellation of the second.
he.expect(
vec![
(
Some(in_connection_result_positive(Id::from(3))),
Some(Output::CancelConnection { id: Id::from(4) }),
),
(None, Some(Output::Succeeded)),
],
now,
);
// User reports an error for the already-cancelled connection.
// This must not panic.
he.expect(
vec![(
Some(in_connection_result_negative(Id::from(4))),
Some(Output::Succeeded),
)],
now,
);
}
#[test]
fn all_connections_failed() {
let (now, mut he) = setup();
he.expect(
vec![
(None, Some(out_send_dns_https(Id::from(0)))),
(None, Some(out_send_dns_aaaa(Id::from(1)))),
(None, Some(out_send_dns_a(Id::from(2)))),
(
Some(in_dns_https_positive_no_alpn(Id::from(0))),
Some(out_resolution_delay()),
),
(
Some(in_dns_aaaa_positive(Id::from(1))),
Some(out_attempt_v6_h1_h2(Id::from(3))),
),
(
Some(in_dns_a_positive(Id::from(2))),
Some(out_connection_attempt_delay()),
),
(
Some(in_connection_result_negative(Id::from(3))),
Some(out_attempt_v4_h1_h2(Id::from(4))),
),
(
Some(in_connection_result_negative(Id::from(4))),
Some(Output::Failed),
),
],
now,
);
}