use std::collections::VecDeque;
use super::*;
struct Scripted {
now: PipeStatus,
later: VecDeque<PipeStatus>,
metrics: NetworkMetrics,
metrics_later: VecDeque<NetworkMetrics>,
}
impl Scripted {
fn new(now: PipeStatus, later: &[PipeStatus]) -> Self {
Self {
now,
later: later.iter().copied().collect(),
metrics: NetworkMetrics::default(),
metrics_later: VecDeque::new(),
}
}
fn reading(mut self, first: NetworkMetrics, later: &[NetworkMetrics]) -> Self {
self.metrics = first;
self.metrics_later = later.iter().copied().collect();
self
}
}
impl AsyncStatus for Scripted {
fn current(&self) -> PipeStatus {
self.now
}
fn metrics(&self) -> NetworkMetrics {
self.metrics
}
async fn changed(&mut self) -> PipeStatus {
match self.later.pop_front() {
Some(next) => {
self.now = next;
if let Some(reading) = self.metrics_later.pop_front() {
self.metrics = reading;
}
next
}
None => std::future::pending().await,
}
}
}
fn reading(total: u64, throttled: u64) -> NetworkMetrics {
let mut metrics = NetworkMetrics::default();
metrics.relay_connections = total;
metrics.relay_connections_ratelimited = throttled;
metrics
}
fn quiet() -> Interrupt {
Interrupt::new().expect("a signal listener")
}
async fn parked(mut status: Scripted) -> String {
let mut out = Vec::new();
park_to(&mut status, &mut quiet(), &mut out)
.await
.expect("a script that closes must end the park cleanly");
String::from_utf8(out).expect("the CLI writes text")
}
const BRIEFLY: Duration = Duration::from_millis(50);
#[tokio::test]
async fn a_pipe_that_is_already_carrying_is_not_waited_for() {
let status = Scripted::new(PipeStatus::Direct, &[]);
first_contact(status, BRIEFLY)
.await
.expect("a connected pipe must not be reported as unreachable");
}
#[tokio::test]
async fn a_pairing_that_forms_a_moment_later_is_waited_for() {
let status = Scripted::new(PipeStatus::Idle, &[PipeStatus::Relayed]);
first_contact(status, BRIEFLY)
.await
.expect("a pipe that connects while waiting has reached its peer");
}
#[tokio::test]
async fn a_serve_side_that_never_answers_is_reported_rather_than_waited_on_for_ever() {
let status = Scripted::new(PipeStatus::Idle, &[]);
let e = first_contact(status, BRIEFLY)
.await
.expect_err("an absent peer must not be reported as reachable");
assert_eq!(
e.to_string(),
"could not reach the serve side, directly or via a relay"
);
}
#[tokio::test]
async fn a_pipe_that_closes_before_it_connects_is_reported_at_once() {
let status = Scripted::new(PipeStatus::Idle, &[PipeStatus::Closed]);
let started = std::time::Instant::now();
let e = first_contact(status, BRIEFLY)
.await
.expect_err("a closed pipe never reached anyone");
assert!(
started.elapsed() < BRIEFLY,
"a terminal state must end the wait rather than run it out"
);
assert_eq!(
e.to_string(),
"could not reach the serve side, directly or via a relay"
);
}
#[test]
fn a_relay_that_is_not_throttling_says_nothing() {
assert_eq!(throttle_line(0, NetworkMetrics::default()), None);
assert_eq!(throttle_line(0, reading(4, 0)), None);
}
#[test]
fn the_first_throttled_connection_is_reported_with_its_denominator() {
assert_eq!(
throttle_line(0, reading(5, 2)).expect("a throttled connection is news"),
"relay: rate limiting this endpoint — 2 of 5 relay connections throttled"
);
}
#[test]
fn a_count_that_has_not_moved_is_not_said_twice() {
assert_eq!(throttle_line(2, reading(5, 2)), None);
assert_eq!(throttle_line(2, reading(5, 1)), None);
}
#[test]
fn a_further_throttled_connection_is_news_again() {
assert_eq!(
throttle_line(2, reading(6, 3)).expect("a third throttled connection is news"),
"relay: rate limiting this endpoint — 3 of 6 relay connections throttled"
);
}
#[test]
fn the_relay_line_aligns_with_the_status_line() {
let relay = throttle_line(0, reading(1, 1)).expect("a throttled connection is news");
let status = "status: relayed";
assert_eq!(
relay.find("rate"),
status.find("relayed"),
"the value columns must agree: {relay:?} vs {status:?}"
);
}
#[tokio::test]
async fn every_status_the_pipe_reaches_is_printed_and_a_clean_relay_adds_nothing() {
let printed = parked(Scripted::new(
PipeStatus::Idle,
&[PipeStatus::Relayed, PipeStatus::Closed],
))
.await;
assert_eq!(printed, "status: idle\nstatus: relayed\nstatus: closed\n");
}
#[tokio::test]
async fn the_relay_throttling_is_printed_under_the_status_it_contradicts_and_only_once() {
let printed = parked(
Scripted::new(PipeStatus::Idle, &[PipeStatus::Relayed, PipeStatus::Closed])
.reading(reading(0, 0), &[reading(3, 1), reading(3, 1)]),
)
.await;
assert_eq!(
printed,
"status: idle\n\
status: relayed\n\
relay: rate limiting this endpoint — 1 of 3 relay connections throttled\n\
status: closed\n"
);
}
#[tokio::test]
async fn throttling_that_predates_the_park_is_reported_and_so_is_the_next_one() {
let printed = parked(
Scripted::new(
PipeStatus::Relayed,
&[PipeStatus::Direct, PipeStatus::Closed],
)
.reading(reading(3, 1), &[reading(4, 2), reading(4, 2)]),
)
.await;
assert_eq!(
printed,
"status: relayed\n\
relay: rate limiting this endpoint — 1 of 3 relay connections throttled\n\
status: direct\n\
relay: rate limiting this endpoint — 2 of 4 relay connections throttled\n\
status: closed\n"
);
}