Load Tester Application

The load tester app is an application made to test DirectX Cube Sample Integration sample. It’s composed of a Node.js application and a Python script. You can customize this app to test your project.

Node.js Test App

This app is written in TypeScript and provides a Websocket implementation and an emulated window object to the Genvid API for it to run in Node.js.

This application is composed of 5 files.

  • config.ts: Global configuration extracted from the environment.
  • common.ts: Common utilities methods that is used by other part of the code.
  • session.ts: Used to test one connection to the Genvid service. It:
    • creates a Genvid client and connects to system,
    • sends events, and
    • gathers metrics and sends them to statsd.
  • cube_client.ts: It contains a customized GenvidSession to be used with a cube sample. Particularly, it contains the implementation of the abstract join method to connect the session to the cluster.
  • index.ts: Entry point to the system. It creates sessions at regular intervals.

The most important section are described below.

The CubeSession class

The CubeSession class extends the GenvidSession class to implement the join method allow sending events. You can access the IGenvidClient() instance through the this.client and add your own stats through the this.statsd member. It is defined in app/src/cube_client.ts.

const cubes = ["Porthos", "Aramis", "Athos"];
const colors = ["green", "white", "yellow", "dark blue", "gray", "light blue", "orange", "blue", "purple"];

// Start of CubeSession class
/**
 * Derived class for customization of the Genvid Session.
 */
export class CubeSession extends GenvidSession {

    /*
     * Call the join method. 
     */
    protected async join(): Promise<genvid.IChannelJoinResponse> {
        const res = await axios.post(config.JOIN_URL);
        const response = res.data as genvid.IChannelJoinResponse;
        if (config.WEBSOCKET_URL) {          
            response.uri = config.WEBSOCKET_URL;
        }
        if (config.NTP_URL) {
            response.info.ntpuri = config.NTP_URL;
        }
        return response;
    }

    public async run() {
        await this.init();
        try {
            await this.start();
            while (true) {
                // Send events every seconds
                this.sendEvent();
                await sleep(1000);
            }
        } catch (err) {
            console.log("Error during session.");
            console.error("Error during session: ", err);
            this.statsd.increment("cube.errors");
            throw err;
        }
    }

    /**
     * Send an event to the system
     */
    public sendEvent(): void {
        if (!this.connected) {
            return;
        }
        try {
            // Send a cheer event
            let cube = cubes[Math.floor((Math.random() * cubes.length))];
            this.client.sendEventObject({ cheer: cube });

            // Send a changeColor event
            let color = colors[Math.floor((Math.random() * colors.length))];
            let evt = {
                key: ["changeColor", cube],
                value: color,
            };
            this.client.sendEvent([evt]);
            this.statsd.increment("cube.sendevents");
        } catch (err) {
            console.log("Send event error");
            console.error("Send event error:", err);
            this.statsd.increment("cube.sendeventerrors");
        }
    }
}

The Load Tester main loop

The main loop of the load tester will do a few thing:

  • Initialize the Genvid library to work in the context of a Node server.
  • Create a loop to display some statistic at regular interval.
  • Create N sessions with a random interval between them, by creating a new session and calling the run method.

See the Configuration file section to know how to modify the loop behavior.

async function main() {
    // Run x connections to the web site, with a random
    // interval between them.
    let promises = []; 
    for (let index = 0; index < config.nbConnection; index++) {
        promises.push(new Session().run());
        const interval = config.intervalMS * (1 + Math.random() * 0.20);
        await sleep(interval);
    }
    return Promise.all(promises);
}

try {
    console.log(`nb connection: ${config.nbConnection}`);
    // Initialize the mock object.
    initMock();
} catch (err) {
    console.log(err);
}

// Print stats every 5 seconds
setInterval(() => {
    Session.printStats();
}, 5000);

main().catch(err => { 
    console.log(`Test execution error: ${err}`);
});

Configuration file

The load tester configuration can be found under config/loadtester.hcl. You will find there the job and log definition for the load tester client, as well as a customization section for relevant parameters:

The relevant section is the following:

config {
  custom {
    loadtester {
      // The number of connection to create
      connections = 10
      // The interval at witch to create session
      interval    = 1000
      // join URL
      join_url = "http://[::1]:30000/api/public/channels/join"
      // websocket URL. Left empty if not use.
      websocket_url = ""
      // NTP url.  Left empty if not use.
      ntp_url = ""
      // Use telegraf format for statsd.
      telegraf = true
    }
  }
}

Python Script

The Python script configures the cluster running the load test. The configurations are in the config/loadtester.hcl file.

The important configurations are:

  • connections: The number of connections.
  • interval: The time interval at which the sessions are created.