| @ -0,0 +1,62 @@ | |||
| //! Provides utilities for testing protocol code. | |||
| use std::io; | |||
| use std::net::SocketAddr; | |||
| use tokio::net::{TcpListener, TcpStream}; | |||
| // use crate::proto::{FrameEncoder, FrameDecoder}; | |||
| async fn process(_stream: TcpStream) -> io::Result<()> { | |||
| Ok(()) | |||
| } | |||
| /// A fake server for connecting to in tests. | |||
| pub struct FakeServer { | |||
| listener: TcpListener, | |||
| } | |||
| impl FakeServer { | |||
| /// Creates a new fake server and binds it to a port on localhost. | |||
| pub async fn new() -> io::Result<Self> { | |||
| let listener = TcpListener::bind("localhost:0").await?; | |||
| Ok(FakeServer { listener }) | |||
| } | |||
| /// Returns the address to which this server is bound. | |||
| /// This is always localhost and a random port chosen by the OS. | |||
| pub fn address(&self) -> io::Result<SocketAddr> { | |||
| self.listener.local_addr() | |||
| } | |||
| /// Runs the server: accepts incoming connections and responds to requests. | |||
| pub async fn run(&mut self) -> io::Result<()> { | |||
| loop { | |||
| let (socket, _peer_address) = self.listener.accept().await?; | |||
| tokio::spawn(async move { process(socket).await }); | |||
| } | |||
| } | |||
| } | |||
| #[cfg(test)] | |||
| mod tests { | |||
| use tokio::net::TcpStream; | |||
| use super::FakeServer; | |||
| #[tokio::test] | |||
| async fn new_binds_to_localhost() { | |||
| let server = FakeServer::new().await.unwrap(); | |||
| assert!(server.address().unwrap().ip().is_loopback()); | |||
| } | |||
| #[tokio::test] | |||
| async fn accepts_incoming_connections() { | |||
| let mut server = FakeServer::new().await.unwrap(); | |||
| let address = server.address().unwrap(); | |||
| tokio::spawn(async move { server.run().await.unwrap() }); | |||
| // The connection succeeds. | |||
| let _ = TcpStream::connect(address).await.unwrap(); | |||
| } | |||
| } | |||