Expand description
§socket-server-mocker
Mock socket server in Rust, for testing various network clients.
I was developing an application that needed to connect to an external server, and I was looking for a way to test the messages sent by the application to the server, directly with cargo test
. So I looked for a way to directly mock a network server in Rust, without having to integrate a real server in docker each time the tests were launched.
With this crate, it is possible to directly test the messages sent by your application which normally connects to a server.
§Usage
Add the socket-server-mocker dependency to your Cargo.toml
for testing compilation:
[dev-dependencies]
socket-server-mocker = "0.3.0"
§Example
You can view all example test codes in tests directory. In particular, you there are examples of mocking the protocols PostgreSQL, HTTP, DNS and SMTP.
Here is a simple example in TCP:
use socket_server_mocker::ServerMocker;
use socket_server_mocker::Instruction::*;
use socket_server_mocker::TcpServerMocker;
use std::io::{Read, Write};
use std::net::TcpStream;
use std::str::from_utf8;
// Mock a TCP server listening on port 35642. Note that the mock will only listen on the local interface.
let tcp_server_mocker = TcpServerMocker::new_with_port(35642).unwrap();
// Create the TCP client to test
let mut client = TcpStream::connect("127.0.0.1:35642").unwrap();
// Mocked server behavior
tcp_server_mocker.add_mock_instructions(vec![
ReceiveMessageWithMaxSize(16), // The mocked server will first wait for the client to send a message
SendMessage("hello from server".as_bytes().to_vec()), // Then it will send a message to the client
]);
// TCP client sends its first message
client.write_all("hello from client".as_bytes()).unwrap();
// Read a message sent by the mocked server
let mut buffer = [0; 1024];
let received_size = client.read(&mut buffer).unwrap();
// convert shrunk buffer to string
let received_message = from_utf8(&buffer[..received_size]).unwrap();
// Check that the message received by the client is the one sent by the mocked server
assert_eq!("hello from server", received_message);
// Check that the mocked server received the message sent by the client
assert_eq!(
"hello from clien", // Max 16 bytes, the word "client" is truncated
from_utf8(tcp_server_mocker.pop_received_message().unwrap().as_ref()).unwrap()
);
// New instructions for the mocked server
tcp_server_mocker.add_mock_instructions(vec![
ReceiveMessage, // Wait for another message from the tested client
SendMessageDependingOnLastReceivedMessage(|_| {
None
}), // No message is sent to the server
SendMessageDependingOnLastReceivedMessage(|last_received_message| {
// "hello2 from client"
let mut received_message_string: String = from_utf8(&last_received_message.unwrap()).unwrap().to_string();
// "hello2"
received_message_string.truncate(5);
Some(format!("{}2 from server", received_message_string).as_bytes().to_vec())
}), // Send a message to the client depending on the last received message by the mocked server
StopExchange, // Finally close the connection
]);
// Tested client send a message to the mocked server
client.write_all("hello2 from client".as_bytes()).unwrap();
// Read a message sent by the mocked server
let mut buffer = [0; 1024];
let received_size = client.read(&mut buffer).unwrap();
// convert shrunk buffer to string
let received_message = from_utf8(&buffer[..received_size]).unwrap();
assert_eq!("hello2 from server", received_message);
assert_eq!(
"hello2 from client",
from_utf8(&*tcp_server_mocker.pop_received_message().unwrap()).unwrap()
);
// Check that no error has been raised by the mocked server
assert!(tcp_server_mocker.pop_server_error().is_none());
Another example in UDP:
use socket_server_mocker::{ServerMocker, UdpServerMocker};
use socket_server_mocker::Instruction::{SendMessage, SendMessageDependingOnLastReceivedMessage, ReceiveMessageWithMaxSize};
use std::net::UdpSocket;
use std::str::from_utf8;
// Mock a UDP server listening on port 35642. Note that the mock will only listen on the local interface.
let udp_server_mocker = UdpServerMocker::new_with_port(35642).unwrap();
// Create the UDP client to test
let client_socket = UdpSocket::bind("127.0.0.1:34254").unwrap();
client_socket.connect("127.0.0.1:35642").unwrap();
// Mocked server behavior
udp_server_mocker.add_mock_instructions(vec![
// The mocked server will first wait for the client to send a message, with max size = 32 bytes
ReceiveMessageWithMaxSize(32),
// Then it will send a message to the client
SendMessage("hello from server".as_bytes().to_vec()),
// Send nothing
SendMessageDependingOnLastReceivedMessage(|_| {
None
}),
// Send a message to the client depending on the last received message by the mocked server
SendMessageDependingOnLastReceivedMessage(|last_received_message| {
// "hello2 from client"
let mut received_message_string: String = from_utf8(&last_received_message.unwrap()).unwrap().to_string();
// "hello2"
received_message_string.truncate(5);
Some(format!("{}2 from server", received_message_string).as_bytes().to_vec())
}),
]
);
// UDP client sends its first message
client_socket.send("hello from client".as_bytes()).unwrap();
// Read a message sent by the mocked server
let mut buffer = [0; 32];
let received_size = client_socket.recv(&mut buffer).unwrap();
// convert shrunk buffer to string
let received_message = from_utf8(&buffer[..received_size]).unwrap();
// Check that the message received by the client is the one sent by the mocked server
assert_eq!("hello from server", received_message);
// Check that the mocked server received the message sent by the client
assert_eq!(
"hello from client",
from_utf8(&*udp_server_mocker.pop_received_message().unwrap()).unwrap()
);
let received_size = client_socket.recv(&mut buffer).unwrap();
// convert shrunk buffer to string
let received_message = from_utf8(&buffer[..received_size]).unwrap();
// Check that the message received by the client is the one sent by the mocked server
assert_eq!("hello2 from server", received_message);
// Check that no error has been raised by the mocked server
assert!(udp_server_mocker.pop_server_error().is_none());
§Development
- This project is easier to develop with just, a modern alternative to
make
. Install it withcargo install just
. - To get a list of available commands, run
just
. - To run tests, use
just test
.
§socket-server-mocker
socket-server-mocker
is a library to mock a socket server.
It can be used to test a code that uses network socket to connect to a server.
#Example
Mock a HTTP server:
use std::str::from_utf8;
use socket_server_mocker::ServerMocker;
use socket_server_mocker::Instruction::{ReceiveMessage, SendMessage, StopExchange};
use socket_server_mocker::TcpServerMocker;
// Mock HTTP server on a random free port
let http_server_mocker = TcpServerMocker::new().unwrap();
http_server_mocker.add_mock_instructions(vec![
// Wait for a HTTP GET request
ReceiveMessage,
// Send a HTTP response
SendMessage("HTTP/1.1 200 OK\r\nServer: socket-server-mocker-fake-http\r\nContent-Length: 12\r\nConnection: close\r\nContent-Type: text/plain\r\n\r\nHello, world".as_bytes().to_vec()),
// Close the connection
StopExchange,
]).unwrap();
// New reqwest blocking client
let client = reqwest::blocking::Client::new();
// Send a HTTP GET request to the mocked server
let response = client
.get(format!(
"http://localhost:{}/",
http_server_mocker.port()
))
.send()
.unwrap();
// Check response status code
assert!(response.status().is_success());
// Check response body
assert_eq!(response.text().unwrap(), "Hello, world");
// Check HTTP request received by the mocked server
assert_eq!(
format!(
"GET / HTTP/1.1\r\naccept: */*\r\nhost: localhost:{}\r\n\r\n",
http_server_mocker.port()
),
from_utf8(&*http_server_mocker.pop_received_message().unwrap()).unwrap()
);
// Check that no error has been raised by the mocked server
assert!(http_server_mocker.pop_server_error().is_none());
Structs§
- A TCP server mocker
- A UDP server mocker
Enums§
- Type of network instruction executed by the server mocker.
- Represents an error raised by a server mocker.
Traits§
- Trait that define the behavior of a network server mocker over an IP layer.