1use crate::metrics::Metrics;
2use std::io::Result;
3use std::net::SocketAddr;
4
5#[async_trait::async_trait]
7pub trait UdpSocketExt: Send + Sync {
8 async fn recv_from(&self, buf: &mut [u8]) -> Result<(usize, SocketAddr)>;
9 async fn send_to(&self, buf: &[u8], target: SocketAddr) -> Result<usize>;
10
11 async fn recv_from_with_metrics(&self, buf: &mut [u8], metrics: &Metrics) -> Result<(usize, SocketAddr)> {
13 let result = self.recv_from(buf).await?;
14 metrics.add_incoming_udp_packet(result.0);
15 Ok(result)
16 }
17
18 async fn send_to_with_metrics(&self, buf: &[u8], target: SocketAddr, metrics: &Metrics) -> Result<usize> {
20 let result = self.send_to(buf, target).await?;
21 metrics.add_outgoing_udp_packet(result);
22 Ok(result)
23 }
24}
25
26#[cfg(test)]
27pub struct MockSocket {
28 recv_data: Vec<u8>,
29 recv_addr: SocketAddr,
30}
31
32#[cfg(test)]
33impl MockSocket {
34 pub fn new() -> Self {
35 Self::with_data_and_src(vec![], "127.0.0.1:1234".parse().unwrap())
36 }
37
38 fn with_data_and_src(recv_data: Vec<u8>, recv_addr: SocketAddr) -> Self {
39 Self { recv_data, recv_addr }
40 }
41}
42
43#[cfg(test)]
44#[async_trait::async_trait]
45impl UdpSocketExt for MockSocket {
46 async fn recv_from(&self, buf: &mut [u8]) -> Result<(usize, SocketAddr)> {
47 let len = self.recv_data.len().min(buf.len());
48 buf[..len].copy_from_slice(&self.recv_data[..len]);
49 Ok((len, self.recv_addr))
50 }
51
52 async fn send_to(&self, buf: &[u8], _target: SocketAddr) -> Result<usize> {
53 Ok(buf.len())
54 }
55}
56
57#[cfg(test)]
58mod tests {
59 use super::*;
60 use crate::metrics::Metrics;
61
62 #[tokio::test]
63 async fn test_recv_from_with_metrics() {
64 let socket = MockSocket::with_data_and_src(vec![1, 2, 3, 4], "127.0.0.1:1234".parse().unwrap());
65 let metrics = Metrics::new();
66 let mut buf = vec![0u8; 10];
67
68 let (len, addr) = socket.recv_from_with_metrics(&mut buf, &metrics).await.unwrap();
69
70 assert_eq!(len, 4);
71 assert_eq!(addr.to_string(), "127.0.0.1:1234");
72
73 let snapshot = metrics.get_snapshot();
75 assert_eq!(snapshot.udp.incoming_packets, 1);
76 assert_eq!(snapshot.udp.incoming_bytes, 4);
77 }
78
79 #[tokio::test]
80 async fn test_send_to_with_metrics() {
81 let socket = MockSocket::with_data_and_src(vec![1, 2, 3, 4], "127.0.0.1:1234".parse().unwrap());
82 let metrics = Metrics::new();
83 let data = vec![1, 2, 3, 4, 5];
84 let target = "127.0.0.1:5678".parse().unwrap();
85
86 let sent = socket.send_to_with_metrics(&data, target, &metrics).await.unwrap();
87
88 assert_eq!(sent, 5);
89
90 let snapshot = metrics.get_snapshot();
92 assert_eq!(snapshot.udp.outgoing_packets, 1);
93 assert_eq!(snapshot.udp.outgoing_bytes, 5);
94 }
95}