Crate socket_server_mocker

Source
Expand description

§socket-server-mocker

GitHub crates.io version docs.rs docs crates.io version CI build

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.5"

§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 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 server = ServerMocker::tcp_with_port(35642).unwrap();

// Create the TCP client to test
let mut client = TcpStream::connect(server.socket_address()).unwrap();

// Mocked server behavior
server.add_mock_instructions(vec![
    ReceiveMessageWithMaxSize(16), // The mocked server will first wait for the client to send a message
    SendMessage(b"hello from server".to_vec()), // Then it will send a message to the client
]);

// TCP client sends its first message
client.write_all(b"hello from client").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(server.pop_received_message().unwrap().as_ref()).unwrap()
);

// New instructions for the mocked server
server.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(b"hello2 from client").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(&*server.pop_received_message().unwrap()).unwrap()
);

// Check that no error has been raised by the mocked server
assert!(server.pop_server_error().is_none());

Another example in UDP:

use socket_server_mocker::ServerMocker;
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 server = ServerMocker::udp_with_port(35642).unwrap();

// Create the UDP client to test at a random port
let client_socket = UdpSocket::bind("127.0.0.1:0").unwrap();
client_socket.connect(server.socket_address()).unwrap();

// Mocked server behavior
server.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(b"hello from server".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(b"hello from client").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(&*server.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!(server.pop_server_error().is_none());

§Development

  • This project is easier to develop with just, a modern alternative to make. Install it with cargo 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 an HTTP server:

use std::str::from_utf8;
use socket_server_mocker::ServerMocker;
use socket_server_mocker::Instruction::{ReceiveMessage, SendMessage, StopExchange};

// Mock HTTP server on a random free port
let server = ServerMocker::tcp().unwrap();

server.add_mock_instructions(vec![
  // Wait for an HTTP GET request
  ReceiveMessage,
  // Send an HTTP response
  SendMessage(b"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".to_vec()),
  // Close the connection
  StopExchange,
]).unwrap();

// New reqwest blocking client
let client = reqwest::blocking::Client::new();
// Send an HTTP GET request to the mocked server
let response = client
  .get(format!("http://localhost:{}/", server.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",
    server.port()
    ),
    from_utf8(&*server.pop_received_message().unwrap()).unwrap()
  );

// Check that no error has been raised by the mocked server
assert!(server.pop_server_error().is_none());

Structs§

ServerMocker
A socket server mocker, able to mock a TCP or UDP server to help test socket connections in a user app.
TcpMocker
Options for the TCP server mocker
UdpMocker
Options for the UDP server mocker

Enums§

Instruction
Type of network instruction executed by the server mocker.
ServerMockerError
Represents an error raised by a server mocker.