use std::net::SocketAddr;
use std::sync::Arc;
use std::time::{Duration, Instant};
use tokio::net::UdpSocket;
use crate::entry::State;
use crate::replica::{send_messages_paced, Message, SendPorts};
use crate::transport::UdpTransport;
use gossip::auth::Authenticator;
type Msg = Message<u64, Vec<u8>, State<u8>>;
fn bulk_updates(n: u64, value_len: usize) -> Vec<Msg> {
(0..n)
.map(|k| Message::Update((k, vec![0u8; value_len])))
.collect()
}
async fn time_send(messages: &[Msg], rate: Option<usize>) -> Duration {
let socket = Arc::new(UdpSocket::bind("127.0.0.1:0").await.unwrap());
let transport = UdpTransport::new(socket);
let authenticator = Authenticator::new(None, false);
let sender_counter = gossip::replay::SenderCounter::new();
let ports = SendPorts {
transport: &transport,
authenticator: &authenticator,
sender_counter: &sender_counter,
};
let peer: SocketAddr = "127.0.0.1:9".parse().unwrap(); let mut send_buf = Vec::new();
let start = Instant::now();
tokio::time::timeout(
Duration::from_secs(10),
send_messages_paced(messages, &ports, &peer, &mut send_buf, rate),
)
.await
.expect("send_messages_paced took over 10s — pacing duration math is almost certainly broken");
start.elapsed()
}
#[tokio::test]
async fn bulk_send_rate_meters_the_transfer() {
let messages = bulk_updates(256, 1024);
let unpaced = time_send(&messages, None).await;
assert!(
unpaced < Duration::from_millis(200),
"unpaced send should be near-instant, took {unpaced:?}"
);
let paced = time_send(&messages, Some(512 * 1024)).await;
assert!(
paced >= Duration::from_millis(300),
"paced send should be metered to ~0.5 s, took {paced:?}"
);
}
#[tokio::test]
async fn zero_or_none_rate_does_not_pace() {
let messages = bulk_updates(256, 1024);
assert!(time_send(&messages, None).await < Duration::from_millis(200));
assert!(time_send(&messages, Some(0)).await < Duration::from_millis(200));
}
#[tokio::test]
async fn tiny_bulk_send_rate_is_clamped_to_the_floor() {
use crate::replica::Replica;
use crate::replicated_map::{Config, MIN_BULK_SEND_RATE};
async fn engine(addr: &str, bulk_send_rate: Option<usize>) -> Replica<i32, i32> {
let config = Config {
bulk_send_rate,
..Config::default()
.with_listen_addr(addr.parse().unwrap())
.with_insecure_no_key()
};
Replica::new(config).await.expect("bind failed")
}
let tiny = engine("127.0.0.80", Some(1)).await;
assert_eq!(tiny.bulk_send_rate, Some(MIN_BULK_SEND_RATE));
let none = engine("127.0.0.81", None).await;
assert_eq!(none.bulk_send_rate, None);
let zero = engine("127.0.0.82", Some(0)).await;
assert_eq!(zero.bulk_send_rate, Some(0));
let above_floor = engine("127.0.0.83", Some(MIN_BULK_SEND_RATE * 2)).await;
assert_eq!(above_floor.bulk_send_rate, Some(MIN_BULK_SEND_RATE * 2));
}
#[tokio::test]
async fn oversized_message_is_dropped_not_sent_empty_or_oversized() {
use crate::transport::{InMemoryNetwork, Transport};
async fn observe_sends(messages: &[Msg]) -> Vec<usize> {
let net = InMemoryNetwork::new();
let sender_addr: SocketAddr = "127.0.0.1:1".parse().unwrap();
let receiver_addr: SocketAddr = "127.0.0.1:2".parse().unwrap();
let sender_transport = net.bind(sender_addr);
let receiver_transport = net.bind(receiver_addr);
let authenticator = Authenticator::new(None, false);
let sender_counter = gossip::replay::SenderCounter::new();
let ports = SendPorts {
transport: &sender_transport,
authenticator: &authenticator,
sender_counter: &sender_counter,
};
let mut send_buf = Vec::new();
send_messages_paced(messages, &ports, &receiver_addr, &mut send_buf, None).await;
let mut sizes = Vec::new();
let mut buf = [0u8; 1 << 17];
while let Ok(Ok((n, _))) = tokio::time::timeout(
Duration::from_millis(50),
receiver_transport.recv_from(&mut buf),
)
.await
{
sizes.push(n);
}
sizes
}
let oversized = vec![Message::Update((
999u64,
vec![0u8; super::super::BUFFER_SIZE * 2],
))];
let small_before = bulk_updates(1, 16);
let small_after = bulk_updates(1, 16);
let mut messages = oversized.clone();
messages.extend(small_after.clone());
let sizes = observe_sends(&messages).await;
assert_eq!(
sizes.len(),
1,
"expected exactly the one normal-sized datagram, got {sizes:?}"
);
assert!(
sizes[0] < super::super::BUFFER_SIZE,
"unexpected datagram size {sizes:?}"
);
let mut messages = small_before;
messages.extend(oversized);
let sizes = observe_sends(&messages).await;
assert_eq!(
sizes.len(),
1,
"expected exactly the one normal-sized datagram, got {sizes:?}"
);
assert!(
sizes[0] < super::super::BUFFER_SIZE,
"unexpected datagram size {sizes:?}"
);
}