socket_server_mocker/
server_mocker.rs

1//! # `server_mocker`
2//!
3//! Mock an IP server for testing application that connect to external server.
4
5use std::net::SocketAddr;
6use std::sync::mpsc;
7use std::sync::mpsc::{Receiver, Sender};
8use std::time::Duration;
9
10use crate::tcp_server::TcpMocker;
11use crate::udp_server::UdpMocker;
12use crate::ServerMockerError::UnableToSendInstructions;
13use crate::{Instruction, ServerMockerError};
14
15/// Options for the mocker, implemented by the specific TCP/UDP backends
16pub trait MockerOptions: Clone {
17    /// Socket address on which the server will listen. Will be set to `127.0.0.1:0` by default.
18    fn socket_address(&self) -> SocketAddr;
19
20    /// Timeout for the server to wait for a message from the client.
21    fn net_timeout(&self) -> Duration;
22
23    /// Run the server mocker with the given instructions
24    fn run(
25        self,
26        instruction_rx: Receiver<Vec<Instruction>>,
27        message_tx: Sender<Vec<u8>>,
28        error_tx: Sender<ServerMockerError>,
29    ) -> Result<SocketAddr, ServerMockerError>;
30}
31
32/// A socket server mocker, able to mock a TCP or UDP server to help test socket connections in a user app.
33///
34/// # TCP Example
35///
36/// ```
37/// use std::io::Write;
38/// use std::net::TcpStream;
39/// use socket_server_mocker::ServerMocker;
40/// use socket_server_mocker::Instruction::{self, ReceiveMessage, StopExchange};
41///
42/// let server = ServerMocker::tcp().unwrap();
43/// let mut client = TcpStream::connect(server.socket_address()).unwrap();
44///
45/// server.add_mock_instructions(vec![
46///     ReceiveMessage,
47///     StopExchange,
48/// ]).unwrap();
49/// client.write_all(&[1, 2, 3]).unwrap();
50///
51/// let mock_server_received_message = server.pop_received_message();
52/// assert_eq!(Some(vec![1, 2, 3]), mock_server_received_message);
53/// assert!(server.pop_server_error().is_none());
54/// assert!(server.pop_server_error().is_none());
55/// ```
56///
57/// # UDP Example
58///
59/// ```
60/// use std::net::{SocketAddr, UdpSocket};
61/// use socket_server_mocker::ServerMocker;
62/// use socket_server_mocker::Instruction::{ReceiveMessage, SendMessage, StopExchange};
63///
64/// let server = ServerMocker::udp().unwrap();
65/// // 0 = random port
66/// let mut client = UdpSocket::bind("127.0.0.1:0").unwrap();
67/// server.add_mock_instructions(vec![
68///    ReceiveMessage,
69///    SendMessage(vec![4, 5, 6]),
70///    StopExchange,
71/// ]).unwrap();
72///
73/// client.send_to(&[1, 2, 3], server.socket_address()).unwrap();
74/// let mut buffer = [0; 3];
75/// client.recv_from(&mut buffer).unwrap();
76/// assert_eq!([4, 5, 6], buffer);
77/// assert_eq!(Some(vec![1, 2, 3]), server.pop_received_message());
78/// assert!(server.pop_server_error().is_none());
79/// ```
80pub struct ServerMocker<T> {
81    options: T,
82    socket_addr: SocketAddr,
83    instruction_tx: Sender<Vec<Instruction>>,
84    message_rx: Receiver<Vec<u8>>,
85    error_rx: Receiver<ServerMockerError>,
86}
87
88impl ServerMocker<TcpMocker> {
89    /// Create a new instance of the UDP server mocker on a random free port.
90    /// The port can be retrieved with the [`ServerMocker::port`] method.
91    pub fn tcp() -> Result<Self, ServerMockerError> {
92        Self::tcp_with_port(0)
93    }
94
95    /// Create a new instance of the UDP server mocker on the given port.
96    /// If the port is already in use, the method will return an error.
97    pub fn tcp_with_port(port: u16) -> Result<Self, ServerMockerError> {
98        let mut opts = TcpMocker::default();
99        opts.socket_addr.set_port(port);
100        Self::new_with_opts(opts)
101    }
102}
103
104impl ServerMocker<UdpMocker> {
105    /// Create a new instance of the UDP server mocker on a random free port.
106    /// The port can be retrieved with the [`ServerMocker::port`] method.
107    pub fn udp() -> Result<Self, ServerMockerError> {
108        Self::udp_with_port(0)
109    }
110
111    /// Create a new instance of the UDP server mocker on the given port.
112    /// If the port is already in use, the method will return an error.
113    pub fn udp_with_port(port: u16) -> Result<Self, ServerMockerError> {
114        let mut opts = UdpMocker::default();
115        opts.socket_addr.set_port(port);
116        Self::new_with_opts(opts)
117    }
118}
119
120impl<T: MockerOptions> ServerMocker<T> {
121    /// Get the options used to create the server mocker
122    pub fn options(&self) -> &T {
123        &self.options
124    }
125
126    /// Get the socket address on which the server is listening
127    pub fn socket_address(&self) -> SocketAddr {
128        self.socket_addr
129    }
130
131    /// Get the port on which the server is listening
132    pub fn port(&self) -> u16 {
133        self.socket_addr.port()
134    }
135
136    /// Add instructions to the server mocker
137    pub fn add_mock_instructions(
138        &self,
139        instructions: Vec<Instruction>,
140    ) -> Result<(), ServerMockerError> {
141        self.instruction_tx
142            .send(instructions)
143            .map_err(UnableToSendInstructions)
144    }
145
146    /// Pop the last received message from the server mocker
147    pub fn pop_received_message(&self) -> Option<Vec<u8>> {
148        self.message_rx
149            .recv_timeout(self.options.net_timeout())
150            .ok()
151    }
152
153    /// Pop the last server error from the server mocker
154    pub fn pop_server_error(&self) -> Option<ServerMockerError> {
155        self.error_rx.recv_timeout(self.options.net_timeout()).ok()
156    }
157
158    /// Create a new instance of the TCP server mocker with the given options.
159    ///
160    /// # Panics
161    /// It is assumed that threads can use messages channels without panicking.
162    pub fn new_with_opts(options: T) -> Result<Self, ServerMockerError> {
163        let (instruction_tx, instruction_rx) = mpsc::channel();
164        let (message_tx, message_rx) = mpsc::channel();
165        let (error_tx, error_rx) = mpsc::channel();
166        let socket_addr = options.clone().run(instruction_rx, message_tx, error_tx)?;
167
168        Ok(Self {
169            options,
170            socket_addr,
171            instruction_tx,
172            message_rx,
173            error_rx,
174        })
175    }
176}