k6

A modern load testing tool, using Go and JavaScript

"like unit testing, for performance"

k6 is a modern load testing tool, building on Load Impact's years of experience. It provides a clean, approachable JavaScript scripting API, distributed and cloud execution, and orchestration via a REST API.

Get Started    Guides

WebSockets

WebSocket is a protocol that provides full-duplex communication channels over a single TCP connection. It is commonly used by single-page apps (SPAs), and to some extent mobile apps, to add server-push based functionality, which usually means a performance improvement over polling based solutions.

Load testing WebSockets with k6

There are some differences in the structure and inner workings of a test when comparing HTTP based to WebSocket based ones. The primary difference is that instead of continuously looping the main function (export default function() { ... }) over an over, each VU is now setup to run an asynchronous event loop.

The basic structure of a WebSocket test looks like this:

import ws from "k6/ws";
import { check } from "k6";

export default function() {
  var url = "ws://echo.websocket.org";
  var params = { "tags": { "my_tag": "hello" } };

  var res = ws.connect(url, params, function(socket) {
    socket.on('open', function() {
      console.log('connected');
    });

    socket.on('message', function(data) {
      console.log("Message received: ", data);
    });

    socket.on('close', function() {
      console.log('disconnected');
    });
  });

  check(res, { "status is 101": (r) => r && r.status === 101 });
}

As you can see above the connect() method takes a "run" function as its third parameter, and that function should accept a Socket object as its only parameter. The run function forms the basis of the asynchronous event loop. It will be called immediately when the WebSocket connection is created, execute all code inside it (usually code to set up event handlers), and then block until the WebSocket connection is closed (by the remote host or by using socket.close()).

Error handling

To catch errors that can happen during the life of a WebSocket connection you attach a handler to the "error" event, as is illustrated below:

import ws from "k6/ws";
import { check } from "k6";

export default function() {
  var url = "ws://echo.websocket.org";
  var params = { "tags": { "my_tag": "hello" } };

  var res = ws.connect(url, params, function(socket) {
    socket.on('open', function open() {
      ...
    });

    socket.on('error', function(e) {
      if (e.error() != "websocket: close sent") {
        console.log('An unexpected error occured: ', e.error());
      }
    });
  });

  check(res, { "status is 101": (r) => r && r.status === 101 });
}

Timers

If you want to schedule a recurring action you can use the socket.setInterval function to specify a function that should be called with a particular interval.

import ws from "k6/ws";
import { check } from "k6";

export default function() {
  var url = "ws://echo.websocket.org";
  var params = { "tags": { "my_tag": "hello" } };

  var res = ws.connect(url, params, function(socket) {
    socket.on('open', function open() {
      console.log('connected');

      socket.setInterval(function timeout() {
        socket.ping();
        console.log("Pinging every 1sec (setInterval test)");
      }, 1000);
    });

    socket.on('ping', function () {
      console.log("PING!");
    });

    socket.on('pong', function () {
      console.log("PONG!");
    });

    socket.on('close', function() {
      console.log('disconnected');
    });
  });

  check(res, { "status is 101": (r) => r && r.status === 101 });
}

Timeouts

You can add a timeout to the WebSocket connection by passing a handler function as well as the timeout value (in milliseconds) to the socket.setTimeout function.

import ws from "k6/ws";
import { check } from "k6";

export default function() {
  var url = "ws://echo.websocket.org";
  var params = { "tags": { "my_tag": "hello" } };

  var res = ws.connect(url, params, function(socket) {
    socket.on('open', function open() {
      console.log('connected');
    });

    socket.on('close', function() {
      console.log('disconnected');
    });

    socket.setTimeout(function() {
      console.log('2 seconds passed, closing the socket');
      socket.close();
    }, 2000);
  });

  check(res, { "status is 101": (r) => r && r.status === 101 });
}

The timeout in the above code will close down the WebSocket connection after 2 seconds.

Multiple event handlers

You can attach multiple handler functions to an event as the code below illustrates.

import ws from "k6/ws";
import { check } from "k6";

export default function() {
  var url = "ws://echo.websocket.org";
  var params = { "tags": { "my_tag": "hello" } };
  
  var response = ws.connect(url, params, function (socket) {
    socket.on('open', function open() {
      console.log('connected');
      socket.send(Date.now());

      socket.setInterval(function timeout() {
        socket.ping();
        console.log("Pinging every 1sec (setInterval test)");
      }, 1000);
    });

    socket.on('ping', function () {
      console.log("PING!");
    });

    socket.on('pong', function () {
      console.log("PONG!");
    });

    socket.on('pong', function () {
      // Multiple event handlers on the same event
      console.log("OTHER PONG!");
    });

    socket.on('close', function close() {
      console.log('disconnected');
    });

    socket.on('error', function (e) {
      if (e.error() != "websocket: close sent") {
        console.log('An unexpected error occured: ', e.error());
      }
    });

    socket.setTimeout(function () {
      console.log('2 seconds passed, closing the socket');
      socket.close();
    }, 2000);
  });

  check(response, { "status is 101": (r) => r && r.status === 101 });
}

WebSockets


Suggested Edits are limited on API Reference Pages

You can only suggest edits to Markdown body content, but not to the API spec.