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}