How to test the WebSocket protocol
Learn how to load test WebSocket with Gatling
WebSocket is a bidirectional communication protocol enabling real-time data exchange between clients and servers. Unlike HTTP, WebSockets maintain a persistent connection for instant, efficient communication. WebSockets are ideal for applications needing real-time updates, like live chat, multiplayer gaming, collaborative editing, in-app notifications, and trading platforms, enhancing user experience and operational efficiency.
Prerequisites
- Gatling version
3.13.5
or higher - Clone the Gatling
devrel
repository and cd into thearticles/websocketguide
folder.
Launch the Server
Let’s create a WebSocket server in JavaScript that we will load test:
const WebSocket = require("ws");
const server = new WebSocket.Server({ port: 8765 });
function send(socket, data, i, n) {
if (i <= n) {
setTimeout(function() {
const message = `${data} ${i}/${n}`;
socket.send(message);
console.log(`-> ${message}`);
send(socket, data, i + 1, n);
}, Math.floor(Math.random() * 1000));
}
}
server.on("connection", (socket) => {
console.log("new client connected");
socket.send("connected");
socket.send("connected");
//socket.on("message", (data) => {
const message = "hello client"
//console.log(`message received: ${message}`);
const n = 5 + Math.floor(Math.random() * 15);
console.log(`responding with ${n} messages`);
send(socket, message, 1, n);
//});
socket.on("close", () => {
console.log("client disconnected");
});
});
console.log("listening on ws://localhost:8765");
This code creates a WebSocket server on port 8765
. When someone connects, it sends a random number of messages with a random interval between 0
and 1
second between each message.
Now let’s load test it.
Test Creation
Create the Scenario
In this guide, we create a scenario using Gatling. Our user connects to the server, checks for incoming messages, and prints the rest of the messages:
package websockets;
import java.nio.charset.StandardCharsets;
import java.util.stream.Collectors;
import static io.gatling.javaapi.core.CoreDsl.*;
import static io.gatling.javaapi.http.HttpDsl.*;
import io.gatling.http.action.ws.WsInboundMessage;
import io.gatling.javaapi.core.*;
import io.gatling.javaapi.http.*;
public class WebSocketSampleJava extends Simulation {
HttpProtocolBuilder httpProtocol =
http.wsBaseUrl("ws://localhost:8765")
.wsUnmatchedInboundMessageBufferSize(1024);
ScenarioBuilder scn = scenario("Users")
.exec(
ws("Connect").connect("/").await(10).on(
ws.checkTextMessage("Connect:check")
.check(bodyString().is("connected"))
),
during(20).on(
ws.processUnmatchedMessages((messages, session) -> {
var data = messages.stream()
.filter(m -> m instanceof WsInboundMessage.Text)
.map(m -> ((WsInboundMessage.Text) m).message())
.collect(Collectors.joining(", "));
System.out.println("messages received last second: " + data);
return session;
}),
pause(1)
),
ws("Close").close()
);
The httpProtocol
allows Gatling to connect to our WebSocket application. After that, we connect to our application and check if the server returns the correct message. ProcessUnmatchedMessage
processes inbound messages that haven’t been matched with a check and have been buffered. In our case, this allows us to display the messages the server sends.
Generate the User
We start with a single user to verify our simulation works correctly. To do that, add the following code to your simulation:
setUp(
scn.injectOpen(atOnceUsers(1))
).protocols(httpProtocol);
Running the Test
To run the simulation:
- Place the simulation file in your project’s test directory.
- Run using Maven:
mvn gatling:test
Best Practices
- Use secure WebSocket connections (wss://).
- Use a buffer or queue to handle incoming messages asynchronously.
- Add appropriate pauses between requests to simulate real user behavior.
- Include proper error handling.
This basic implementation should get you started with load testing WebSocket applications. If you need a more detailed use case, you can see the list of available commands here.